File Index
Files and directories
Sign in
FILE

ntp8835.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/codecs/ntp8835.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Driver for the NTP8835/NTP8835C Audio Amplifiers
  4 *
  5 * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
  6 *
  7 * Author: Igor Prusov <ivprusov@salutedevices.com>
  8 */
  9
 10#include <linux/kernel.h>
 11#include <linux/clk.h>
 12#include <linux/bits.h>
 13#include <linux/reset.h>
 14#include <linux/init.h>
 15#include <linux/i2c.h>
 16#include <linux/regmap.h>
 17
 18#include <sound/initval.h>
 19#include <sound/core.h>
 20#include <sound/pcm.h>
 21#include <sound/pcm_params.h>
 22#include <sound/soc.h>
 23#include <sound/soc-component.h>
 24#include <sound/tlv.h>
 25
 26#include "ntpfw.h"
 27
 28#define NTP8835_FORMATS     (SNDRV_PCM_FMTBIT_S16_LE | \
 29			     SNDRV_PCM_FMTBIT_S20_3LE | \
 30			     SNDRV_PCM_FMTBIT_S24_LE | \
 31			     SNDRV_PCM_FMTBIT_S32_LE)
 32
 33#define NTP8835_INPUT_FMT			0x0
 34#define  NTP8835_INPUT_FMT_MASTER_MODE		BIT(0)
 35#define  NTP8835_INPUT_FMT_GSA_MODE		BIT(1)
 36#define NTP8835_GSA_FMT				0x1
 37#define  NTP8835_GSA_BS_MASK			GENMASK(3, 2)
 38#define  NTP8835_GSA_BS(x)			((x) << 2)
 39#define  NTP8835_GSA_RIGHT_J			BIT(0)
 40#define  NTP8835_GSA_LSB			BIT(1)
 41#define NTP8835_MCLK_FREQ_CTRL			0x2
 42#define  NTP8835_MCLK_FREQ_MCF			GENMASK(1, 0)
 43#define NTP8835_SOFT_MUTE			0x26
 44#define  NTP8835_SOFT_MUTE_SM1			BIT(0)
 45#define  NTP8835_SOFT_MUTE_SM2			BIT(1)
 46#define  NTP8835_SOFT_MUTE_SM3			BIT(2)
 47#define NTP8835_PWM_SWITCH			0x27
 48#define  NTP8835_PWM_SWITCH_POF1		BIT(0)
 49#define  NTP8835_PWM_SWITCH_POF2		BIT(1)
 50#define  NTP8835_PWM_SWITCH_POF3		BIT(2)
 51#define NTP8835_PWM_MASK_CTRL0			0x28
 52#define  NTP8835_PWM_MASK_CTRL0_OUT_LOW		BIT(1)
 53#define  NTP8835_PWM_MASK_CTRL0_FPMLD		BIT(2)
 54#define NTP8835_MASTER_VOL			0x2e
 55#define NTP8835_CHNL_A_VOL			0x2f
 56#define NTP8835_CHNL_B_VOL			0x30
 57#define NTP8835_CHNL_C_VOL			0x31
 58#define REG_MAX					NTP8835_CHNL_C_VOL
 59
 60#define NTP8835_FW_NAME				"eq_8835.bin"
 61#define NTP8835_FW_MAGIC			0x38383335	/* "8835" */
 62
 63struct ntp8835_priv {
 64	struct i2c_client *i2c;
 65	struct reset_control *reset;
 66	unsigned int format;
 67	struct clk *mclk;
 68	unsigned int mclk_rate;
 69};
 70
 71static const DECLARE_TLV_DB_RANGE(ntp8835_vol_scale,
 72	0, 1, TLV_DB_SCALE_ITEM(-15000, 0, 0),
 73	2, 6, TLV_DB_SCALE_ITEM(-15000, 1000, 0),
 74	7, 0xff, TLV_DB_SCALE_ITEM(-10000, 50, 0),
 75);
 76
 77static int ntp8835_mute_info(struct snd_kcontrol *kcontrol,
 78			     struct snd_ctl_elem_info *uinfo)
 79{
 80	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 81	uinfo->access =
 82		(SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE);
 83	uinfo->count = 1;
 84
 85	uinfo->value.integer.min = 0;
 86	uinfo->value.integer.max = 1;
 87	uinfo->value.integer.step = 1;
 88
 89	return 0;
 90}
 91
 92static int ntp8835_mute_get(struct snd_kcontrol *kcontrol,
 93			    struct snd_ctl_elem_value *ucontrol)
 94{
 95	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
 96	unsigned int val;
 97
 98	val = snd_soc_component_read(component, NTP8835_SOFT_MUTE);
 99
100	ucontrol->value.integer.value[0] = val ? 0 : 1;
101	return 0;
102}
103
104static int ntp8835_mute_put(struct snd_kcontrol *kcontrol,
105			    struct snd_ctl_elem_value *ucontrol)
106{
107	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
108	unsigned int val;
109
110	val = ucontrol->value.integer.value[0] ? 0 : 7;
111
112	snd_soc_component_write(component, NTP8835_SOFT_MUTE, val);
113
114	return 0;
115}
116
117static const struct snd_kcontrol_new ntp8835_vol_control[] = {
118	SOC_SINGLE_TLV("Playback Volume", NTP8835_MASTER_VOL, 0,
119		       0xff, 0, ntp8835_vol_scale),
120	{
121		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
122		.name = "Playback Switch",
123		.info = ntp8835_mute_info,
124		.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,
125		.get = ntp8835_mute_get,
126		.put = ntp8835_mute_put,
127	},
128};
129
130static void ntp8835_reset_gpio(struct ntp8835_priv *ntp8835)
131{
132	/*
133	 * Proper initialization sequence for NTP835 amplifier requires driving
134	 * /RESET signal low during power up for at least 0.1us. The sequence is,
135	 * according to NTP8835 datasheet, 6.2 Timing Sequence (recommended):
136	 * Deassert for T2 >= 1ms...
137	 */
138	reset_control_deassert(ntp8835->reset);
139	fsleep(1000);
140
141	/* ...Assert for T3 >= 0.1us... */
142	reset_control_assert(ntp8835->reset);
143	fsleep(1);
144
145	/* ...Deassert, and wait for T4 >= 0.5ms before sound on sequence. */
146	reset_control_deassert(ntp8835->reset);
147	fsleep(500);
148}
149
150static const struct reg_sequence ntp8835_sound_on[] = {
151	{ NTP8835_PWM_MASK_CTRL0,	NTP8835_PWM_MASK_CTRL0_FPMLD },
152	{ NTP8835_PWM_SWITCH,		0x00 },
153	{ NTP8835_SOFT_MUTE,		0x00 },
154};
155
156static const struct reg_sequence ntp8835_sound_off[] = {
157	{ NTP8835_SOFT_MUTE,		NTP8835_SOFT_MUTE_SM1 |
158					NTP8835_SOFT_MUTE_SM2 |
159					NTP8835_SOFT_MUTE_SM3 },
160
161	{ NTP8835_PWM_SWITCH,		NTP8835_PWM_SWITCH_POF1 |
162					NTP8835_PWM_SWITCH_POF2 |
163					NTP8835_PWM_SWITCH_POF3 },
164
165	{ NTP8835_PWM_MASK_CTRL0,	NTP8835_PWM_MASK_CTRL0_OUT_LOW |
166					NTP8835_PWM_MASK_CTRL0_FPMLD },
167};
168
169static int ntp8835_load_firmware(struct ntp8835_priv *ntp8835)
170{
171	int ret;
172
173	ret = ntpfw_load(ntp8835->i2c, NTP8835_FW_NAME, NTP8835_FW_MAGIC);
174	if (ret == -ENOENT) {
175		dev_warn_once(&ntp8835->i2c->dev,
176			      "Could not find firmware %s\n", NTP8835_FW_NAME);
177		return 0;
178	}
179
180	return ret;
181}
182
183static int ntp8835_snd_suspend(struct snd_soc_component *component)
184{
185	struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
186
187	regcache_cache_only(component->regmap, true);
188
189	regmap_multi_reg_write_bypassed(component->regmap,
190					ntp8835_sound_off,
191					ARRAY_SIZE(ntp8835_sound_off));
192
193	/*
194	 * According to NTP8835 datasheet, 6.2 Timing Sequence (recommended):
195	 * wait after sound off for T6 >= 0.5ms
196	 */
197	fsleep(500);
198	reset_control_assert(ntp8835->reset);
199
200	regcache_mark_dirty(component->regmap);
201	clk_disable_unprepare(ntp8835->mclk);
202
203	return 0;
204}
205
206static int ntp8835_snd_resume(struct snd_soc_component *component)
207{
208	struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
209	int ret;
210
211	ntp8835_reset_gpio(ntp8835);
212	ret = clk_prepare_enable(ntp8835->mclk);
213	if (ret)
214		return ret;
215
216	regmap_multi_reg_write_bypassed(component->regmap,
217					ntp8835_sound_on,
218					ARRAY_SIZE(ntp8835_sound_on));
219
220	ret = ntp8835_load_firmware(ntp8835);
221	if (ret) {
222		dev_err(&ntp8835->i2c->dev, "Failed to load firmware\n");
223		return ret;
224	}
225
226	regcache_cache_only(component->regmap, false);
227	snd_soc_component_cache_sync(component);
228
229	return 0;
230}
231
232static int ntp8835_probe(struct snd_soc_component *component)
233{
234	int ret;
235	struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
236	struct device *dev = component->dev;
237
238	ret = snd_soc_add_component_controls(component, ntp8835_vol_control,
239					     ARRAY_SIZE(ntp8835_vol_control));
240	if (ret)
241		return dev_err_probe(dev, ret, "Failed to add controls\n");
242
243	ret = ntp8835_load_firmware(ntp8835);
244	if (ret)
245		return dev_err_probe(dev, ret, "Failed to load firmware\n");
246
247	return 0;
248}
249
250static const struct snd_soc_dapm_widget ntp8835_dapm_widgets[] = {
251	SND_SOC_DAPM_DAC("AIFIN", "Playback", SND_SOC_NOPM, 0, 0),
252
253	SND_SOC_DAPM_OUTPUT("OUT1"),
254	SND_SOC_DAPM_OUTPUT("OUT2"),
255	SND_SOC_DAPM_OUTPUT("OUT3"),
256};
257
258static const struct snd_soc_dapm_route ntp8835_dapm_routes[] = {
259	{ "OUT1", NULL, "AIFIN" },
260	{ "OUT2", NULL, "AIFIN" },
261	{ "OUT3", NULL, "AIFIN" },
262};
263
264static int ntp8835_set_component_sysclk(struct snd_soc_component *component,
265				       int clk_id, int source,
266				       unsigned int freq, int dir)
267{
268	struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
269
270	switch (freq) {
271	case 12288000:
272	case 24576000:
273	case 18432000:
274		ntp8835->mclk_rate = freq;
275		break;
276	default:
277		ntp8835->mclk_rate = 0;
278		dev_err(component->dev, "Unsupported MCLK value: %u", freq);
279		return -EINVAL;
280	}
281
282	return 0;
283}
284
285static const struct snd_soc_component_driver soc_component_ntp8835 = {
286	.probe = ntp8835_probe,
287	.suspend = ntp8835_snd_suspend,
288	.resume = ntp8835_snd_resume,
289	.dapm_widgets = ntp8835_dapm_widgets,
290	.num_dapm_widgets = ARRAY_SIZE(ntp8835_dapm_widgets),
291	.dapm_routes = ntp8835_dapm_routes,
292	.num_dapm_routes = ARRAY_SIZE(ntp8835_dapm_routes),
293	.set_sysclk = ntp8835_set_component_sysclk,
294};
295
296static int ntp8835_hw_params(struct snd_pcm_substream *substream,
297			     struct snd_pcm_hw_params *params,
298			     struct snd_soc_dai *dai)
299{
300	struct snd_soc_component *component = dai->component;
301	struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
302	unsigned int input_fmt = 0;
303	unsigned int gsa_fmt = 0;
304	unsigned int gsa_fmt_mask;
305	unsigned int mcf;
306	int ret;
307
308	switch (ntp8835->mclk_rate) {
309	case 12288000:
310		mcf = 0;
311		break;
312	case 24576000:
313		mcf = 1;
314		break;
315	case 18432000:
316		mcf = 2;
317		break;
318	default:
319		return -EINVAL;
320	}
321
322	ret = snd_soc_component_update_bits(component, NTP8835_MCLK_FREQ_CTRL,
323					    NTP8835_MCLK_FREQ_MCF, mcf);
324	if (ret)
325		return ret;
326
327	switch (ntp8835->format) {
328	case SND_SOC_DAIFMT_I2S:
329		break;
330	case SND_SOC_DAIFMT_RIGHT_J:
331		input_fmt |= NTP8835_INPUT_FMT_GSA_MODE;
332		gsa_fmt |= NTP8835_GSA_RIGHT_J;
333		break;
334	case SND_SOC_DAIFMT_LEFT_J:
335		input_fmt |= NTP8835_INPUT_FMT_GSA_MODE;
336		break;
337	}
338
339	ret = snd_soc_component_update_bits(component, NTP8835_INPUT_FMT,
340					    NTP8835_INPUT_FMT_MASTER_MODE |
341					    NTP8835_INPUT_FMT_GSA_MODE,
342					    input_fmt);
343
344	if (!(input_fmt & NTP8835_INPUT_FMT_GSA_MODE) || ret < 0)
345		return ret;
346
347	switch (params_width(params)) {
348	case 24:
349		gsa_fmt |= NTP8835_GSA_BS(0);
350		break;
351	case 20:
352		gsa_fmt |= NTP8835_GSA_BS(1);
353		break;
354	case 18:
355		gsa_fmt |= NTP8835_GSA_BS(2);
356		break;
357	case 16:
358		gsa_fmt |= NTP8835_GSA_BS(3);
359		break;
360	default:
361		return -EINVAL;
362	}
363
364	gsa_fmt_mask = NTP8835_GSA_BS_MASK |
365		       NTP8835_GSA_RIGHT_J |
366		       NTP8835_GSA_LSB;
367	return snd_soc_component_update_bits(component, NTP8835_GSA_FMT,
368					     gsa_fmt_mask, gsa_fmt);
369}
370
371static int ntp8835_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
372{
373	struct snd_soc_component *component = dai->component;
374	struct ntp8835_priv *ntp8835 = snd_soc_component_get_drvdata(component);
375
376	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
377	case SND_SOC_DAIFMT_I2S:
378	case SND_SOC_DAIFMT_RIGHT_J:
379	case SND_SOC_DAIFMT_LEFT_J:
380		ntp8835->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
381		break;
382	default:
383		return -EINVAL;
384	}
385	return 0;
386};
387
388static const struct snd_soc_dai_ops ntp8835_dai_ops = {
389	.hw_params = ntp8835_hw_params,
390	.set_fmt = ntp8835_set_fmt,
391};
392
393static struct snd_soc_dai_driver ntp8835_dai = {
394	.name = "ntp8835-amplifier",
395	.playback = {
396		.stream_name = "Playback",
397		.channels_min = 1,
398		.channels_max = 3,
399		.rates = SNDRV_PCM_RATE_8000_192000,
400		.formats = NTP8835_FORMATS,
401	},
402	.ops = &ntp8835_dai_ops,
403};
404
405static const struct regmap_config ntp8835_regmap = {
406	.reg_bits = 8,
407	.val_bits = 8,
408	.max_register = REG_MAX,
409	.cache_type = REGCACHE_MAPLE,
410};
411
412static int ntp8835_i2c_probe(struct i2c_client *i2c)
413{
414	struct ntp8835_priv *ntp8835;
415	struct regmap *regmap;
416	int ret;
417
418	ntp8835 = devm_kzalloc(&i2c->dev, sizeof(*ntp8835), GFP_KERNEL);
419	if (!ntp8835)
420		return -ENOMEM;
421
422	ntp8835->i2c = i2c;
423
424	ntp8835->reset = devm_reset_control_get_shared(&i2c->dev, NULL);
425	if (IS_ERR(ntp8835->reset))
426		return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->reset),
427				     "Failed to get reset\n");
428
429	ret = reset_control_deassert(ntp8835->reset);
430	if (ret)
431		return dev_err_probe(&i2c->dev, ret,
432				     "Failed to deassert reset\n");
433
434	dev_set_drvdata(&i2c->dev, ntp8835);
435
436	ntp8835_reset_gpio(ntp8835);
437
438	regmap = devm_regmap_init_i2c(i2c, &ntp8835_regmap);
439	if (IS_ERR(regmap))
440		return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
441				     "Failed to allocate regmap\n");
442
443	ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_ntp8835,
444					      &ntp8835_dai, 1);
445	if (ret)
446		return dev_err_probe(&i2c->dev, ret,
447				     "Failed to register component\n");
448
449	ntp8835->mclk = devm_clk_get_enabled(&i2c->dev, "mclk");
450	if (IS_ERR(ntp8835->mclk))
451		return dev_err_probe(&i2c->dev, PTR_ERR(ntp8835->mclk), "failed to get mclk\n");
452
453	return 0;
454}
455
456static const struct i2c_device_id ntp8835_i2c_id[] = {
457	{ "ntp8835" },
458	{}
459};
460MODULE_DEVICE_TABLE(i2c, ntp8835_i2c_id);
461
462static const struct of_device_id ntp8835_of_match[] = {
463	{.compatible = "neofidelity,ntp8835",},
464	{}
465};
466MODULE_DEVICE_TABLE(of, ntp8835_of_match);
467
468static struct i2c_driver ntp8835_i2c_driver = {
469	.probe = ntp8835_i2c_probe,
470	.id_table = ntp8835_i2c_id,
471	.driver = {
472		.name = "ntp8835",
473		.of_match_table = ntp8835_of_match,
474	},
475};
476module_i2c_driver(ntp8835_i2c_driver);
477
478MODULE_AUTHOR("Igor Prusov <ivprusov@salutedevices.com>");
479MODULE_DESCRIPTION("NTP8835 Audio Amplifier Driver");
480MODULE_LICENSE("GPL");
~/ Read-only file preview.