162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Wolfson WM97xx -- Core device
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2017 Robert Jarzmik
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Features:
862306a36Sopenharmony_ci *  - an AC97 audio codec
962306a36Sopenharmony_ci *  - a touchscreen driver
1062306a36Sopenharmony_ci *  - a GPIO block
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/mfd/core.h>
1562306a36Sopenharmony_ci#include <linux/mfd/wm97xx.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/wm97xx.h>
2062306a36Sopenharmony_ci#include <sound/ac97/codec.h>
2162306a36Sopenharmony_ci#include <sound/ac97/compat.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define WM9705_VENDOR_ID 0x574d4c05
2462306a36Sopenharmony_ci#define WM9712_VENDOR_ID 0x574d4c12
2562306a36Sopenharmony_ci#define WM9713_VENDOR_ID 0x574d4c13
2662306a36Sopenharmony_ci#define WM97xx_VENDOR_ID_MASK 0xffffffff
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct wm97xx_priv {
2962306a36Sopenharmony_ci	struct regmap *regmap;
3062306a36Sopenharmony_ci	struct snd_ac97 *ac97;
3162306a36Sopenharmony_ci	struct device *dev;
3262306a36Sopenharmony_ci	struct wm97xx_platform_data codec_pdata;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic bool wm97xx_readable_reg(struct device *dev, unsigned int reg)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	switch (reg) {
3862306a36Sopenharmony_ci	case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:
3962306a36Sopenharmony_ci	case AC97_PCM_LR_ADC_RATE:
4062306a36Sopenharmony_ci	case AC97_CENTER_LFE_MASTER:
4162306a36Sopenharmony_ci	case AC97_SPDIF ... AC97_LINE1_LEVEL:
4262306a36Sopenharmony_ci	case AC97_GPIO_CFG ... 0x5c:
4362306a36Sopenharmony_ci	case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:
4462306a36Sopenharmony_ci	case 0x74 ... AC97_VENDOR_ID2:
4562306a36Sopenharmony_ci		return true;
4662306a36Sopenharmony_ci	default:
4762306a36Sopenharmony_ci		return false;
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic bool wm97xx_writeable_reg(struct device *dev, unsigned int reg)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	switch (reg) {
5462306a36Sopenharmony_ci	case AC97_VENDOR_ID1:
5562306a36Sopenharmony_ci	case AC97_VENDOR_ID2:
5662306a36Sopenharmony_ci		return false;
5762306a36Sopenharmony_ci	default:
5862306a36Sopenharmony_ci		return wm97xx_readable_reg(dev, reg);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic const struct reg_default wm9705_reg_defaults[] = {
6362306a36Sopenharmony_ci	{ 0x02, 0x8000 },
6462306a36Sopenharmony_ci	{ 0x04, 0x8000 },
6562306a36Sopenharmony_ci	{ 0x06, 0x8000 },
6662306a36Sopenharmony_ci	{ 0x0a, 0x8000 },
6762306a36Sopenharmony_ci	{ 0x0c, 0x8008 },
6862306a36Sopenharmony_ci	{ 0x0e, 0x8008 },
6962306a36Sopenharmony_ci	{ 0x10, 0x8808 },
7062306a36Sopenharmony_ci	{ 0x12, 0x8808 },
7162306a36Sopenharmony_ci	{ 0x14, 0x8808 },
7262306a36Sopenharmony_ci	{ 0x16, 0x8808 },
7362306a36Sopenharmony_ci	{ 0x18, 0x8808 },
7462306a36Sopenharmony_ci	{ 0x1a, 0x0000 },
7562306a36Sopenharmony_ci	{ 0x1c, 0x8000 },
7662306a36Sopenharmony_ci	{ 0x20, 0x0000 },
7762306a36Sopenharmony_ci	{ 0x22, 0x0000 },
7862306a36Sopenharmony_ci	{ 0x26, 0x000f },
7962306a36Sopenharmony_ci	{ 0x28, 0x0605 },
8062306a36Sopenharmony_ci	{ 0x2a, 0x0000 },
8162306a36Sopenharmony_ci	{ 0x2c, 0xbb80 },
8262306a36Sopenharmony_ci	{ 0x32, 0xbb80 },
8362306a36Sopenharmony_ci	{ 0x34, 0x2000 },
8462306a36Sopenharmony_ci	{ 0x5a, 0x0000 },
8562306a36Sopenharmony_ci	{ 0x5c, 0x0000 },
8662306a36Sopenharmony_ci	{ 0x72, 0x0808 },
8762306a36Sopenharmony_ci	{ 0x74, 0x0000 },
8862306a36Sopenharmony_ci	{ 0x76, 0x0006 },
8962306a36Sopenharmony_ci	{ 0x78, 0x0000 },
9062306a36Sopenharmony_ci	{ 0x7a, 0x0000 },
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic const struct regmap_config wm9705_regmap_config = {
9462306a36Sopenharmony_ci	.reg_bits = 16,
9562306a36Sopenharmony_ci	.reg_stride = 2,
9662306a36Sopenharmony_ci	.val_bits = 16,
9762306a36Sopenharmony_ci	.max_register = 0x7e,
9862306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	.reg_defaults = wm9705_reg_defaults,
10162306a36Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults),
10262306a36Sopenharmony_ci	.volatile_reg = regmap_ac97_default_volatile,
10362306a36Sopenharmony_ci	.readable_reg = wm97xx_readable_reg,
10462306a36Sopenharmony_ci	.writeable_reg = wm97xx_writeable_reg,
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic struct mfd_cell wm9705_cells[] = {
10862306a36Sopenharmony_ci	{ .name = "wm9705-codec", },
10962306a36Sopenharmony_ci	{ .name = "wm97xx-ts", },
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic bool wm9712_volatile_reg(struct device *dev, unsigned int reg)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	switch (reg) {
11562306a36Sopenharmony_ci	case AC97_REC_GAIN:
11662306a36Sopenharmony_ci		return true;
11762306a36Sopenharmony_ci	default:
11862306a36Sopenharmony_ci		return regmap_ac97_default_volatile(dev, reg);
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const struct reg_default wm9712_reg_defaults[] = {
12362306a36Sopenharmony_ci	{ 0x02, 0x8000 },
12462306a36Sopenharmony_ci	{ 0x04, 0x8000 },
12562306a36Sopenharmony_ci	{ 0x06, 0x8000 },
12662306a36Sopenharmony_ci	{ 0x08, 0x0f0f },
12762306a36Sopenharmony_ci	{ 0x0a, 0xaaa0 },
12862306a36Sopenharmony_ci	{ 0x0c, 0xc008 },
12962306a36Sopenharmony_ci	{ 0x0e, 0x6808 },
13062306a36Sopenharmony_ci	{ 0x10, 0xe808 },
13162306a36Sopenharmony_ci	{ 0x12, 0xaaa0 },
13262306a36Sopenharmony_ci	{ 0x14, 0xad00 },
13362306a36Sopenharmony_ci	{ 0x16, 0x8000 },
13462306a36Sopenharmony_ci	{ 0x18, 0xe808 },
13562306a36Sopenharmony_ci	{ 0x1a, 0x3000 },
13662306a36Sopenharmony_ci	{ 0x1c, 0x8000 },
13762306a36Sopenharmony_ci	{ 0x20, 0x0000 },
13862306a36Sopenharmony_ci	{ 0x22, 0x0000 },
13962306a36Sopenharmony_ci	{ 0x26, 0x000f },
14062306a36Sopenharmony_ci	{ 0x28, 0x0605 },
14162306a36Sopenharmony_ci	{ 0x2a, 0x0410 },
14262306a36Sopenharmony_ci	{ 0x2c, 0xbb80 },
14362306a36Sopenharmony_ci	{ 0x2e, 0xbb80 },
14462306a36Sopenharmony_ci	{ 0x32, 0xbb80 },
14562306a36Sopenharmony_ci	{ 0x34, 0x2000 },
14662306a36Sopenharmony_ci	{ 0x4c, 0xf83e },
14762306a36Sopenharmony_ci	{ 0x4e, 0xffff },
14862306a36Sopenharmony_ci	{ 0x50, 0x0000 },
14962306a36Sopenharmony_ci	{ 0x52, 0x0000 },
15062306a36Sopenharmony_ci	{ 0x56, 0xf83e },
15162306a36Sopenharmony_ci	{ 0x58, 0x0008 },
15262306a36Sopenharmony_ci	{ 0x5c, 0x0000 },
15362306a36Sopenharmony_ci	{ 0x60, 0xb032 },
15462306a36Sopenharmony_ci	{ 0x62, 0x3e00 },
15562306a36Sopenharmony_ci	{ 0x64, 0x0000 },
15662306a36Sopenharmony_ci	{ 0x76, 0x0006 },
15762306a36Sopenharmony_ci	{ 0x78, 0x0001 },
15862306a36Sopenharmony_ci	{ 0x7a, 0x0000 },
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic const struct regmap_config wm9712_regmap_config = {
16262306a36Sopenharmony_ci	.reg_bits = 16,
16362306a36Sopenharmony_ci	.reg_stride = 2,
16462306a36Sopenharmony_ci	.val_bits = 16,
16562306a36Sopenharmony_ci	.max_register = 0x7e,
16662306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	.reg_defaults = wm9712_reg_defaults,
16962306a36Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),
17062306a36Sopenharmony_ci	.volatile_reg = wm9712_volatile_reg,
17162306a36Sopenharmony_ci	.readable_reg = wm97xx_readable_reg,
17262306a36Sopenharmony_ci	.writeable_reg = wm97xx_writeable_reg,
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic struct mfd_cell wm9712_cells[] = {
17662306a36Sopenharmony_ci	{ .name = "wm9712-codec", },
17762306a36Sopenharmony_ci	{ .name = "wm97xx-ts", },
17862306a36Sopenharmony_ci};
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic const struct reg_default wm9713_reg_defaults[] = {
18162306a36Sopenharmony_ci	{ 0x02, 0x8080 },	/* Speaker Output Volume */
18262306a36Sopenharmony_ci	{ 0x04, 0x8080 },	/* Headphone Output Volume */
18362306a36Sopenharmony_ci	{ 0x06, 0x8080 },	/* Out3/OUT4 Volume */
18462306a36Sopenharmony_ci	{ 0x08, 0xc880 },	/* Mono Volume */
18562306a36Sopenharmony_ci	{ 0x0a, 0xe808 },	/* LINEIN Volume */
18662306a36Sopenharmony_ci	{ 0x0c, 0xe808 },	/* DAC PGA Volume */
18762306a36Sopenharmony_ci	{ 0x0e, 0x0808 },	/* MIC PGA Volume */
18862306a36Sopenharmony_ci	{ 0x10, 0x00da },	/* MIC Routing Control */
18962306a36Sopenharmony_ci	{ 0x12, 0x8000 },	/* Record PGA Volume */
19062306a36Sopenharmony_ci	{ 0x14, 0xd600 },	/* Record Routing */
19162306a36Sopenharmony_ci	{ 0x16, 0xaaa0 },	/* PCBEEP Volume */
19262306a36Sopenharmony_ci	{ 0x18, 0xaaa0 },	/* VxDAC Volume */
19362306a36Sopenharmony_ci	{ 0x1a, 0xaaa0 },	/* AUXDAC Volume */
19462306a36Sopenharmony_ci	{ 0x1c, 0x0000 },	/* Output PGA Mux */
19562306a36Sopenharmony_ci	{ 0x1e, 0x0000 },	/* DAC 3D control */
19662306a36Sopenharmony_ci	{ 0x20, 0x0f0f },	/* DAC Tone Control*/
19762306a36Sopenharmony_ci	{ 0x22, 0x0040 },	/* MIC Input Select & Bias */
19862306a36Sopenharmony_ci	{ 0x24, 0x0000 },	/* Output Volume Mapping & Jack */
19962306a36Sopenharmony_ci	{ 0x26, 0x7f00 },	/* Powerdown Ctrl/Stat*/
20062306a36Sopenharmony_ci	{ 0x28, 0x0405 },	/* Extended Audio ID */
20162306a36Sopenharmony_ci	{ 0x2a, 0x0410 },	/* Extended Audio Start/Ctrl */
20262306a36Sopenharmony_ci	{ 0x2c, 0xbb80 },	/* Audio DACs Sample Rate */
20362306a36Sopenharmony_ci	{ 0x2e, 0xbb80 },	/* AUXDAC Sample Rate */
20462306a36Sopenharmony_ci	{ 0x32, 0xbb80 },	/* Audio ADCs Sample Rate */
20562306a36Sopenharmony_ci	{ 0x36, 0x4523 },	/* PCM codec control */
20662306a36Sopenharmony_ci	{ 0x3a, 0x2000 },	/* SPDIF control */
20762306a36Sopenharmony_ci	{ 0x3c, 0xfdff },	/* Powerdown 1 */
20862306a36Sopenharmony_ci	{ 0x3e, 0xffff },	/* Powerdown 2 */
20962306a36Sopenharmony_ci	{ 0x40, 0x0000 },	/* General Purpose */
21062306a36Sopenharmony_ci	{ 0x42, 0x0000 },	/* Fast Power-Up Control */
21162306a36Sopenharmony_ci	{ 0x44, 0x0080 },	/* MCLK/PLL Control */
21262306a36Sopenharmony_ci	{ 0x46, 0x0000 },	/* MCLK/PLL Control */
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	{ 0x4c, 0xfffe },	/* GPIO Pin Configuration */
21562306a36Sopenharmony_ci	{ 0x4e, 0xffff },	/* GPIO Pin Polarity / Type */
21662306a36Sopenharmony_ci	{ 0x50, 0x0000 },	/* GPIO Pin Sticky */
21762306a36Sopenharmony_ci	{ 0x52, 0x0000 },	/* GPIO Pin Wake-Up */
21862306a36Sopenharmony_ci				/* GPIO Pin Status */
21962306a36Sopenharmony_ci	{ 0x56, 0xfffe },	/* GPIO Pin Sharing */
22062306a36Sopenharmony_ci	{ 0x58, 0x4000 },	/* GPIO PullUp/PullDown */
22162306a36Sopenharmony_ci	{ 0x5a, 0x0000 },	/* Additional Functions 1 */
22262306a36Sopenharmony_ci	{ 0x5c, 0x0000 },	/* Additional Functions 2 */
22362306a36Sopenharmony_ci	{ 0x60, 0xb032 },	/* ALC Control */
22462306a36Sopenharmony_ci	{ 0x62, 0x3e00 },	/* ALC / Noise Gate Control */
22562306a36Sopenharmony_ci	{ 0x64, 0x0000 },	/* AUXDAC input control */
22662306a36Sopenharmony_ci	{ 0x74, 0x0000 },	/* Digitiser Reg 1 */
22762306a36Sopenharmony_ci	{ 0x76, 0x0006 },	/* Digitiser Reg 2 */
22862306a36Sopenharmony_ci	{ 0x78, 0x0001 },	/* Digitiser Reg 3 */
22962306a36Sopenharmony_ci	{ 0x7a, 0x0000 },	/* Digitiser Read Back */
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic const struct regmap_config wm9713_regmap_config = {
23362306a36Sopenharmony_ci	.reg_bits = 16,
23462306a36Sopenharmony_ci	.reg_stride = 2,
23562306a36Sopenharmony_ci	.val_bits = 16,
23662306a36Sopenharmony_ci	.max_register = 0x7e,
23762306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	.reg_defaults = wm9713_reg_defaults,
24062306a36Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
24162306a36Sopenharmony_ci	.volatile_reg = regmap_ac97_default_volatile,
24262306a36Sopenharmony_ci	.readable_reg = wm97xx_readable_reg,
24362306a36Sopenharmony_ci	.writeable_reg = wm97xx_writeable_reg,
24462306a36Sopenharmony_ci};
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic struct mfd_cell wm9713_cells[] = {
24762306a36Sopenharmony_ci	{ .name = "wm9713-codec", },
24862306a36Sopenharmony_ci	{ .name = "wm97xx-ts", },
24962306a36Sopenharmony_ci};
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int wm97xx_ac97_probe(struct ac97_codec_device *adev)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct wm97xx_priv *wm97xx;
25462306a36Sopenharmony_ci	const struct regmap_config *config;
25562306a36Sopenharmony_ci	struct wm97xx_platform_data *codec_pdata;
25662306a36Sopenharmony_ci	struct mfd_cell *cells;
25762306a36Sopenharmony_ci	int ret = -ENODEV, nb_cells, i;
25862306a36Sopenharmony_ci	struct wm97xx_pdata *pdata = snd_ac97_codec_get_platdata(adev);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	wm97xx = devm_kzalloc(ac97_codec_dev2dev(adev),
26162306a36Sopenharmony_ci			      sizeof(*wm97xx), GFP_KERNEL);
26262306a36Sopenharmony_ci	if (!wm97xx)
26362306a36Sopenharmony_ci		return -ENOMEM;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	wm97xx->dev = ac97_codec_dev2dev(adev);
26662306a36Sopenharmony_ci	wm97xx->ac97 = snd_ac97_compat_alloc(adev);
26762306a36Sopenharmony_ci	if (IS_ERR(wm97xx->ac97))
26862306a36Sopenharmony_ci		return PTR_ERR(wm97xx->ac97);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	ac97_set_drvdata(adev, wm97xx);
27262306a36Sopenharmony_ci	dev_info(wm97xx->dev, "wm97xx core found, id=0x%x\n",
27362306a36Sopenharmony_ci		 adev->vendor_id);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	codec_pdata = &wm97xx->codec_pdata;
27662306a36Sopenharmony_ci	codec_pdata->ac97 = wm97xx->ac97;
27762306a36Sopenharmony_ci	codec_pdata->batt_pdata = pdata ? pdata->batt_pdata : NULL;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	switch (adev->vendor_id) {
28062306a36Sopenharmony_ci	case WM9705_VENDOR_ID:
28162306a36Sopenharmony_ci		config = &wm9705_regmap_config;
28262306a36Sopenharmony_ci		cells = wm9705_cells;
28362306a36Sopenharmony_ci		nb_cells = ARRAY_SIZE(wm9705_cells);
28462306a36Sopenharmony_ci		break;
28562306a36Sopenharmony_ci	case WM9712_VENDOR_ID:
28662306a36Sopenharmony_ci		config = &wm9712_regmap_config;
28762306a36Sopenharmony_ci		cells = wm9712_cells;
28862306a36Sopenharmony_ci		nb_cells = ARRAY_SIZE(wm9712_cells);
28962306a36Sopenharmony_ci		break;
29062306a36Sopenharmony_ci	case WM9713_VENDOR_ID:
29162306a36Sopenharmony_ci		config = &wm9713_regmap_config;
29262306a36Sopenharmony_ci		cells = wm9713_cells;
29362306a36Sopenharmony_ci		nb_cells = ARRAY_SIZE(wm9713_cells);
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci	default:
29662306a36Sopenharmony_ci		goto err_free_compat;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	for (i = 0; i < nb_cells; i++) {
30062306a36Sopenharmony_ci		cells[i].platform_data = codec_pdata;
30162306a36Sopenharmony_ci		cells[i].pdata_size = sizeof(*codec_pdata);
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	codec_pdata->regmap = devm_regmap_init_ac97(wm97xx->ac97, config);
30562306a36Sopenharmony_ci	if (IS_ERR(codec_pdata->regmap)) {
30662306a36Sopenharmony_ci		ret = PTR_ERR(codec_pdata->regmap);
30762306a36Sopenharmony_ci		goto err_free_compat;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = devm_mfd_add_devices(wm97xx->dev, PLATFORM_DEVID_NONE,
31162306a36Sopenharmony_ci				   cells, nb_cells, NULL, 0, NULL);
31262306a36Sopenharmony_ci	if (ret)
31362306a36Sopenharmony_ci		goto err_free_compat;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return ret;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cierr_free_compat:
31862306a36Sopenharmony_ci	snd_ac97_compat_release(wm97xx->ac97);
31962306a36Sopenharmony_ci	return ret;
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic void wm97xx_ac97_remove(struct ac97_codec_device *adev)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct wm97xx_priv *wm97xx = ac97_get_drvdata(adev);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	snd_ac97_compat_release(wm97xx->ac97);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic const struct ac97_id wm97xx_ac97_ids[] = {
33062306a36Sopenharmony_ci	{ .id = WM9705_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
33162306a36Sopenharmony_ci	{ .id = WM9712_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
33262306a36Sopenharmony_ci	{ .id = WM9713_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
33362306a36Sopenharmony_ci	{ }
33462306a36Sopenharmony_ci};
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic struct ac97_codec_driver wm97xx_ac97_driver = {
33762306a36Sopenharmony_ci	.driver = {
33862306a36Sopenharmony_ci		.name = "wm97xx-core",
33962306a36Sopenharmony_ci	},
34062306a36Sopenharmony_ci	.probe		= wm97xx_ac97_probe,
34162306a36Sopenharmony_ci	.remove		= wm97xx_ac97_remove,
34262306a36Sopenharmony_ci	.id_table	= wm97xx_ac97_ids,
34362306a36Sopenharmony_ci};
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int __init wm97xx_module_init(void)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	return snd_ac97_codec_driver_register(&wm97xx_ac97_driver);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_cimodule_init(wm97xx_module_init);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void __exit wm97xx_module_exit(void)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	snd_ac97_codec_driver_unregister(&wm97xx_ac97_driver);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_cimodule_exit(wm97xx_module_exit);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ciMODULE_DESCRIPTION("WM9712, WM9713 core driver");
35862306a36Sopenharmony_ciMODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
35962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
36062306a36Sopenharmony_ci
361