brintos

brintos / linux-shallow public Read only

0
0
Text · 9.0 KiB · 1566a9b Raw
361 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Wolfson WM97xx -- Core device4 *5 * Copyright (C) 2017 Robert Jarzmik6 *7 * Features:8 *  - an AC97 audio codec9 *  - a touchscreen driver10 *  - a GPIO block11 */12 13#include <linux/device.h>14#include <linux/mfd/core.h>15#include <linux/mfd/wm97xx.h>16#include <linux/module.h>17#include <linux/regmap.h>18#include <linux/slab.h>19#include <linux/wm97xx.h>20#include <sound/ac97/codec.h>21#include <sound/ac97/compat.h>22 23#define WM9705_VENDOR_ID 0x574d4c0524#define WM9712_VENDOR_ID 0x574d4c1225#define WM9713_VENDOR_ID 0x574d4c1326#define WM97xx_VENDOR_ID_MASK 0xffffffff27 28struct wm97xx_priv {29	struct regmap *regmap;30	struct snd_ac97 *ac97;31	struct device *dev;32	struct wm97xx_platform_data codec_pdata;33};34 35static bool wm97xx_readable_reg(struct device *dev, unsigned int reg)36{37	switch (reg) {38	case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:39	case AC97_PCM_LR_ADC_RATE:40	case AC97_CENTER_LFE_MASTER:41	case AC97_SPDIF ... AC97_LINE1_LEVEL:42	case AC97_GPIO_CFG ... 0x5c:43	case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:44	case 0x74 ... AC97_VENDOR_ID2:45		return true;46	default:47		return false;48	}49}50 51static bool wm97xx_writeable_reg(struct device *dev, unsigned int reg)52{53	switch (reg) {54	case AC97_VENDOR_ID1:55	case AC97_VENDOR_ID2:56		return false;57	default:58		return wm97xx_readable_reg(dev, reg);59	}60}61 62static const struct reg_default wm9705_reg_defaults[] = {63	{ 0x02, 0x8000 },64	{ 0x04, 0x8000 },65	{ 0x06, 0x8000 },66	{ 0x0a, 0x8000 },67	{ 0x0c, 0x8008 },68	{ 0x0e, 0x8008 },69	{ 0x10, 0x8808 },70	{ 0x12, 0x8808 },71	{ 0x14, 0x8808 },72	{ 0x16, 0x8808 },73	{ 0x18, 0x8808 },74	{ 0x1a, 0x0000 },75	{ 0x1c, 0x8000 },76	{ 0x20, 0x0000 },77	{ 0x22, 0x0000 },78	{ 0x26, 0x000f },79	{ 0x28, 0x0605 },80	{ 0x2a, 0x0000 },81	{ 0x2c, 0xbb80 },82	{ 0x32, 0xbb80 },83	{ 0x34, 0x2000 },84	{ 0x5a, 0x0000 },85	{ 0x5c, 0x0000 },86	{ 0x72, 0x0808 },87	{ 0x74, 0x0000 },88	{ 0x76, 0x0006 },89	{ 0x78, 0x0000 },90	{ 0x7a, 0x0000 },91};92 93static const struct regmap_config wm9705_regmap_config = {94	.reg_bits = 16,95	.reg_stride = 2,96	.val_bits = 16,97	.max_register = 0x7e,98	.cache_type = REGCACHE_MAPLE,99 100	.reg_defaults = wm9705_reg_defaults,101	.num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults),102	.volatile_reg = regmap_ac97_default_volatile,103	.readable_reg = wm97xx_readable_reg,104	.writeable_reg = wm97xx_writeable_reg,105};106 107static struct mfd_cell wm9705_cells[] = {108	{ .name = "wm9705-codec", },109	{ .name = "wm97xx-ts", },110};111 112static bool wm9712_volatile_reg(struct device *dev, unsigned int reg)113{114	switch (reg) {115	case AC97_REC_GAIN:116		return true;117	default:118		return regmap_ac97_default_volatile(dev, reg);119	}120}121 122static const struct reg_default wm9712_reg_defaults[] = {123	{ 0x02, 0x8000 },124	{ 0x04, 0x8000 },125	{ 0x06, 0x8000 },126	{ 0x08, 0x0f0f },127	{ 0x0a, 0xaaa0 },128	{ 0x0c, 0xc008 },129	{ 0x0e, 0x6808 },130	{ 0x10, 0xe808 },131	{ 0x12, 0xaaa0 },132	{ 0x14, 0xad00 },133	{ 0x16, 0x8000 },134	{ 0x18, 0xe808 },135	{ 0x1a, 0x3000 },136	{ 0x1c, 0x8000 },137	{ 0x20, 0x0000 },138	{ 0x22, 0x0000 },139	{ 0x26, 0x000f },140	{ 0x28, 0x0605 },141	{ 0x2a, 0x0410 },142	{ 0x2c, 0xbb80 },143	{ 0x2e, 0xbb80 },144	{ 0x32, 0xbb80 },145	{ 0x34, 0x2000 },146	{ 0x4c, 0xf83e },147	{ 0x4e, 0xffff },148	{ 0x50, 0x0000 },149	{ 0x52, 0x0000 },150	{ 0x56, 0xf83e },151	{ 0x58, 0x0008 },152	{ 0x5c, 0x0000 },153	{ 0x60, 0xb032 },154	{ 0x62, 0x3e00 },155	{ 0x64, 0x0000 },156	{ 0x76, 0x0006 },157	{ 0x78, 0x0001 },158	{ 0x7a, 0x0000 },159};160 161static const struct regmap_config wm9712_regmap_config = {162	.reg_bits = 16,163	.reg_stride = 2,164	.val_bits = 16,165	.max_register = 0x7e,166	.cache_type = REGCACHE_MAPLE,167 168	.reg_defaults = wm9712_reg_defaults,169	.num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),170	.volatile_reg = wm9712_volatile_reg,171	.readable_reg = wm97xx_readable_reg,172	.writeable_reg = wm97xx_writeable_reg,173};174 175static struct mfd_cell wm9712_cells[] = {176	{ .name = "wm9712-codec", },177	{ .name = "wm97xx-ts", },178};179 180static const struct reg_default wm9713_reg_defaults[] = {181	{ 0x02, 0x8080 },	/* Speaker Output Volume */182	{ 0x04, 0x8080 },	/* Headphone Output Volume */183	{ 0x06, 0x8080 },	/* Out3/OUT4 Volume */184	{ 0x08, 0xc880 },	/* Mono Volume */185	{ 0x0a, 0xe808 },	/* LINEIN Volume */186	{ 0x0c, 0xe808 },	/* DAC PGA Volume */187	{ 0x0e, 0x0808 },	/* MIC PGA Volume */188	{ 0x10, 0x00da },	/* MIC Routing Control */189	{ 0x12, 0x8000 },	/* Record PGA Volume */190	{ 0x14, 0xd600 },	/* Record Routing */191	{ 0x16, 0xaaa0 },	/* PCBEEP Volume */192	{ 0x18, 0xaaa0 },	/* VxDAC Volume */193	{ 0x1a, 0xaaa0 },	/* AUXDAC Volume */194	{ 0x1c, 0x0000 },	/* Output PGA Mux */195	{ 0x1e, 0x0000 },	/* DAC 3D control */196	{ 0x20, 0x0f0f },	/* DAC Tone Control*/197	{ 0x22, 0x0040 },	/* MIC Input Select & Bias */198	{ 0x24, 0x0000 },	/* Output Volume Mapping & Jack */199	{ 0x26, 0x7f00 },	/* Powerdown Ctrl/Stat*/200	{ 0x28, 0x0405 },	/* Extended Audio ID */201	{ 0x2a, 0x0410 },	/* Extended Audio Start/Ctrl */202	{ 0x2c, 0xbb80 },	/* Audio DACs Sample Rate */203	{ 0x2e, 0xbb80 },	/* AUXDAC Sample Rate */204	{ 0x32, 0xbb80 },	/* Audio ADCs Sample Rate */205	{ 0x36, 0x4523 },	/* PCM codec control */206	{ 0x3a, 0x2000 },	/* SPDIF control */207	{ 0x3c, 0xfdff },	/* Powerdown 1 */208	{ 0x3e, 0xffff },	/* Powerdown 2 */209	{ 0x40, 0x0000 },	/* General Purpose */210	{ 0x42, 0x0000 },	/* Fast Power-Up Control */211	{ 0x44, 0x0080 },	/* MCLK/PLL Control */212	{ 0x46, 0x0000 },	/* MCLK/PLL Control */213 214	{ 0x4c, 0xfffe },	/* GPIO Pin Configuration */215	{ 0x4e, 0xffff },	/* GPIO Pin Polarity / Type */216	{ 0x50, 0x0000 },	/* GPIO Pin Sticky */217	{ 0x52, 0x0000 },	/* GPIO Pin Wake-Up */218				/* GPIO Pin Status */219	{ 0x56, 0xfffe },	/* GPIO Pin Sharing */220	{ 0x58, 0x4000 },	/* GPIO PullUp/PullDown */221	{ 0x5a, 0x0000 },	/* Additional Functions 1 */222	{ 0x5c, 0x0000 },	/* Additional Functions 2 */223	{ 0x60, 0xb032 },	/* ALC Control */224	{ 0x62, 0x3e00 },	/* ALC / Noise Gate Control */225	{ 0x64, 0x0000 },	/* AUXDAC input control */226	{ 0x74, 0x0000 },	/* Digitiser Reg 1 */227	{ 0x76, 0x0006 },	/* Digitiser Reg 2 */228	{ 0x78, 0x0001 },	/* Digitiser Reg 3 */229	{ 0x7a, 0x0000 },	/* Digitiser Read Back */230};231 232static const struct regmap_config wm9713_regmap_config = {233	.reg_bits = 16,234	.reg_stride = 2,235	.val_bits = 16,236	.max_register = 0x7e,237	.cache_type = REGCACHE_MAPLE,238 239	.reg_defaults = wm9713_reg_defaults,240	.num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),241	.volatile_reg = regmap_ac97_default_volatile,242	.readable_reg = wm97xx_readable_reg,243	.writeable_reg = wm97xx_writeable_reg,244};245 246static struct mfd_cell wm9713_cells[] = {247	{ .name = "wm9713-codec", },248	{ .name = "wm97xx-ts", },249};250 251static int wm97xx_ac97_probe(struct ac97_codec_device *adev)252{253	struct wm97xx_priv *wm97xx;254	const struct regmap_config *config;255	struct wm97xx_platform_data *codec_pdata;256	struct mfd_cell *cells;257	int ret = -ENODEV, nb_cells, i;258	struct wm97xx_pdata *pdata = snd_ac97_codec_get_platdata(adev);259 260	wm97xx = devm_kzalloc(ac97_codec_dev2dev(adev),261			      sizeof(*wm97xx), GFP_KERNEL);262	if (!wm97xx)263		return -ENOMEM;264 265	wm97xx->dev = ac97_codec_dev2dev(adev);266	wm97xx->ac97 = snd_ac97_compat_alloc(adev);267	if (IS_ERR(wm97xx->ac97))268		return PTR_ERR(wm97xx->ac97);269 270 271	ac97_set_drvdata(adev, wm97xx);272	dev_info(wm97xx->dev, "wm97xx core found, id=0x%x\n",273		 adev->vendor_id);274 275	codec_pdata = &wm97xx->codec_pdata;276	codec_pdata->ac97 = wm97xx->ac97;277	codec_pdata->batt_pdata = pdata ? pdata->batt_pdata : NULL;278 279	switch (adev->vendor_id) {280	case WM9705_VENDOR_ID:281		config = &wm9705_regmap_config;282		cells = wm9705_cells;283		nb_cells = ARRAY_SIZE(wm9705_cells);284		break;285	case WM9712_VENDOR_ID:286		config = &wm9712_regmap_config;287		cells = wm9712_cells;288		nb_cells = ARRAY_SIZE(wm9712_cells);289		break;290	case WM9713_VENDOR_ID:291		config = &wm9713_regmap_config;292		cells = wm9713_cells;293		nb_cells = ARRAY_SIZE(wm9713_cells);294		break;295	default:296		goto err_free_compat;297	}298 299	for (i = 0; i < nb_cells; i++) {300		cells[i].platform_data = codec_pdata;301		cells[i].pdata_size = sizeof(*codec_pdata);302	}303 304	codec_pdata->regmap = devm_regmap_init_ac97(wm97xx->ac97, config);305	if (IS_ERR(codec_pdata->regmap)) {306		ret = PTR_ERR(codec_pdata->regmap);307		goto err_free_compat;308	}309 310	ret = devm_mfd_add_devices(wm97xx->dev, PLATFORM_DEVID_NONE,311				   cells, nb_cells, NULL, 0, NULL);312	if (ret)313		goto err_free_compat;314 315	return ret;316 317err_free_compat:318	snd_ac97_compat_release(wm97xx->ac97);319	return ret;320}321 322static void wm97xx_ac97_remove(struct ac97_codec_device *adev)323{324	struct wm97xx_priv *wm97xx = ac97_get_drvdata(adev);325 326	snd_ac97_compat_release(wm97xx->ac97);327}328 329static const struct ac97_id wm97xx_ac97_ids[] = {330	{ .id = WM9705_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },331	{ .id = WM9712_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },332	{ .id = WM9713_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },333	{ }334};335 336static struct ac97_codec_driver wm97xx_ac97_driver = {337	.driver = {338		.name = "wm97xx-core",339	},340	.probe		= wm97xx_ac97_probe,341	.remove		= wm97xx_ac97_remove,342	.id_table	= wm97xx_ac97_ids,343};344 345static int __init wm97xx_module_init(void)346{347	return snd_ac97_codec_driver_register(&wm97xx_ac97_driver);348}349module_init(wm97xx_module_init);350 351static void __exit wm97xx_module_exit(void)352{353	snd_ac97_codec_driver_unregister(&wm97xx_ac97_driver);354}355module_exit(wm97xx_module_exit);356 357MODULE_DESCRIPTION("WM9712, WM9713 core driver");358MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");359MODULE_LICENSE("GPL");360 361