Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * ak4118.c  --  Asahi Kasei ALSA Soc Audio driver
  4 *
  5 * Copyright 2018 DEVIALET
  6 */
  7
  8#include <linux/i2c.h>
  9#include <linux/gpio/consumer.h>
 10#include <linux/module.h>
 11#include <linux/of.h>
 
 12#include <linux/regmap.h>
 13#include <linux/slab.h>
 14
 15#include <sound/asoundef.h>
 16#include <sound/core.h>
 17#include <sound/initval.h>
 18#include <sound/soc.h>
 19
 20#define AK4118_REG_CLK_PWR_CTL		0x00
 21#define AK4118_REG_FORMAT_CTL		0x01
 22#define AK4118_REG_IO_CTL0		0x02
 23#define AK4118_REG_IO_CTL1		0x03
 24#define AK4118_REG_INT0_MASK		0x04
 25#define AK4118_REG_INT1_MASK		0x05
 26#define AK4118_REG_RCV_STATUS0		0x06
 27#define AK4118_REG_RCV_STATUS1		0x07
 28#define AK4118_REG_RXCHAN_STATUS0	0x08
 29#define AK4118_REG_RXCHAN_STATUS1	0x09
 30#define AK4118_REG_RXCHAN_STATUS2	0x0a
 31#define AK4118_REG_RXCHAN_STATUS3	0x0b
 32#define AK4118_REG_RXCHAN_STATUS4	0x0c
 33#define AK4118_REG_TXCHAN_STATUS0	0x0d
 34#define AK4118_REG_TXCHAN_STATUS1	0x0e
 35#define AK4118_REG_TXCHAN_STATUS2	0x0f
 36#define AK4118_REG_TXCHAN_STATUS3	0x10
 37#define AK4118_REG_TXCHAN_STATUS4	0x11
 38#define AK4118_REG_BURST_PREAMB_PC0	0x12
 39#define AK4118_REG_BURST_PREAMB_PC1	0x13
 40#define AK4118_REG_BURST_PREAMB_PD0	0x14
 41#define AK4118_REG_BURST_PREAMB_PD1	0x15
 42#define AK4118_REG_QSUB_CTL		0x16
 43#define AK4118_REG_QSUB_TRACK		0x17
 44#define AK4118_REG_QSUB_INDEX		0x18
 45#define AK4118_REG_QSUB_MIN		0x19
 46#define AK4118_REG_QSUB_SEC		0x1a
 47#define AK4118_REG_QSUB_FRAME		0x1b
 48#define AK4118_REG_QSUB_ZERO		0x1c
 49#define AK4118_REG_QSUB_ABS_MIN		0x1d
 50#define AK4118_REG_QSUB_ABS_SEC		0x1e
 51#define AK4118_REG_QSUB_ABS_FRAME	0x1f
 52#define AK4118_REG_GPE			0x20
 53#define AK4118_REG_GPDR			0x21
 54#define AK4118_REG_GPSCR		0x22
 55#define AK4118_REG_GPLR			0x23
 56#define AK4118_REG_DAT_MASK_DTS		0x24
 57#define AK4118_REG_RX_DETECT		0x25
 58#define AK4118_REG_STC_DAT_DETECT	0x26
 59#define AK4118_REG_RXCHAN_STATUS5	0x27
 60#define AK4118_REG_TXCHAN_STATUS5	0x28
 61#define AK4118_REG_MAX			0x29
 62
 63#define AK4118_REG_FORMAT_CTL_DIF0	(1 << 4)
 64#define AK4118_REG_FORMAT_CTL_DIF1	(1 << 5)
 65#define AK4118_REG_FORMAT_CTL_DIF2	(1 << 6)
 66
 67struct ak4118_priv {
 68	struct regmap *regmap;
 69	struct gpio_desc *reset;
 70	struct gpio_desc *irq;
 71	struct snd_soc_component *component;
 72};
 73
 74static const struct reg_default ak4118_reg_defaults[] = {
 75	{AK4118_REG_CLK_PWR_CTL,	0x43},
 76	{AK4118_REG_FORMAT_CTL,		0x6a},
 77	{AK4118_REG_IO_CTL0,		0x88},
 78	{AK4118_REG_IO_CTL1,		0x48},
 79	{AK4118_REG_INT0_MASK,		0xee},
 80	{AK4118_REG_INT1_MASK,		0xb5},
 81	{AK4118_REG_RCV_STATUS0,	0x00},
 82	{AK4118_REG_RCV_STATUS1,	0x10},
 83	{AK4118_REG_TXCHAN_STATUS0,	0x00},
 84	{AK4118_REG_TXCHAN_STATUS1,	0x00},
 85	{AK4118_REG_TXCHAN_STATUS2,	0x00},
 86	{AK4118_REG_TXCHAN_STATUS3,	0x00},
 87	{AK4118_REG_TXCHAN_STATUS4,	0x00},
 88	{AK4118_REG_GPE,		0x77},
 89	{AK4118_REG_GPDR,		0x00},
 90	{AK4118_REG_GPSCR,		0x00},
 91	{AK4118_REG_GPLR,		0x00},
 92	{AK4118_REG_DAT_MASK_DTS,	0x3f},
 93	{AK4118_REG_RX_DETECT,		0x00},
 94	{AK4118_REG_STC_DAT_DETECT,	0x00},
 95	{AK4118_REG_TXCHAN_STATUS5,	0x00},
 96};
 97
 98static const char * const ak4118_input_select_txt[] = {
 99	"RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
100};
101static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
102			    ak4118_input_select_txt);
103
104static const struct snd_kcontrol_new ak4118_input_mux_controls =
105	SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
106
107static const char * const ak4118_iec958_fs_txt[] = {
108	"44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
109	"8000", "96000", "64000", "176400", "192000",
110};
111
112static const int ak4118_iec958_fs_val[] = {
113	0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
114};
115
116static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
117				  0x4, 0x4, ak4118_iec958_fs_txt,
118				  ak4118_iec958_fs_val);
119
120static struct snd_kcontrol_new ak4118_iec958_controls[] = {
121	SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
122	SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
123	SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
124	SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
125	SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
126};
127
128static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
129	SND_SOC_DAPM_INPUT("INRX0"),
130	SND_SOC_DAPM_INPUT("INRX1"),
131	SND_SOC_DAPM_INPUT("INRX2"),
132	SND_SOC_DAPM_INPUT("INRX3"),
133	SND_SOC_DAPM_INPUT("INRX4"),
134	SND_SOC_DAPM_INPUT("INRX5"),
135	SND_SOC_DAPM_INPUT("INRX6"),
136	SND_SOC_DAPM_INPUT("INRX7"),
137	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
138			 &ak4118_input_mux_controls),
139};
140
141static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
142	{"Input Mux", "RX0", "INRX0"},
143	{"Input Mux", "RX1", "INRX1"},
144	{"Input Mux", "RX2", "INRX2"},
145	{"Input Mux", "RX3", "INRX3"},
146	{"Input Mux", "RX4", "INRX4"},
147	{"Input Mux", "RX5", "INRX5"},
148	{"Input Mux", "RX6", "INRX6"},
149	{"Input Mux", "RX7", "INRX7"},
150};
151
152
153static int ak4118_set_dai_fmt_provider(struct ak4118_priv *ak4118,
154				       unsigned int format)
155{
156	int dif;
157
158	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
159	case SND_SOC_DAIFMT_I2S:
160		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
161		break;
162	case SND_SOC_DAIFMT_RIGHT_J:
163		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
164		break;
165	case SND_SOC_DAIFMT_LEFT_J:
166		dif = AK4118_REG_FORMAT_CTL_DIF2;
167		break;
168	default:
169		return -ENOTSUPP;
170	}
171
172	return dif;
173}
174
175static int ak4118_set_dai_fmt_consumer(struct ak4118_priv *ak4118,
176				       unsigned int format)
177{
178	int dif;
179
180	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
181	case SND_SOC_DAIFMT_I2S:
182		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
183		      AK4118_REG_FORMAT_CTL_DIF2;
184		break;
185	case SND_SOC_DAIFMT_LEFT_J:
186		dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
187		break;
188	default:
189		return -ENOTSUPP;
190	}
191
192	return dif;
193}
194
195static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
196			      unsigned int format)
197{
198	struct snd_soc_component *component = dai->component;
199	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
200	int dif;
201	int ret = 0;
202
203	switch (format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
204	case SND_SOC_DAIFMT_CBP_CFP:
205		dif = ak4118_set_dai_fmt_provider(ak4118, format);
 
206		break;
207	case SND_SOC_DAIFMT_CBC_CFC:
208		dif = ak4118_set_dai_fmt_consumer(ak4118, format);
 
209		break;
210	default:
211		ret = -ENOTSUPP;
212		goto exit;
213	}
214
215	/* format not supported */
216	if (dif < 0) {
217		ret = dif;
218		goto exit;
219	}
220
221	ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
222				 AK4118_REG_FORMAT_CTL_DIF0 |
223				 AK4118_REG_FORMAT_CTL_DIF1 |
224				 AK4118_REG_FORMAT_CTL_DIF2, dif);
225	if (ret < 0)
226		goto exit;
227
228exit:
229	return ret;
230}
231
232static int ak4118_hw_params(struct snd_pcm_substream *substream,
233			    struct snd_pcm_hw_params *params,
234			    struct snd_soc_dai *dai)
235{
236	return 0;
237}
238
239static const struct snd_soc_dai_ops ak4118_dai_ops = {
240	.hw_params = ak4118_hw_params,
241	.set_fmt   = ak4118_set_dai_fmt,
242};
243
244static struct snd_soc_dai_driver ak4118_dai = {
245	.name = "ak4118-hifi",
246	.capture = {
247		.stream_name = "Capture",
248		.channels_min = 2,
249		.channels_max = 2,
250		.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
251			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
252			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
253			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
254		.formats = SNDRV_PCM_FMTBIT_S16_LE  |
255			   SNDRV_PCM_FMTBIT_S24_3LE |
256			   SNDRV_PCM_FMTBIT_S24_LE
257	},
258	.ops = &ak4118_dai_ops,
259};
260
261static irqreturn_t ak4118_irq_handler(int irq, void *data)
262{
263	struct ak4118_priv *ak4118 = data;
264	struct snd_soc_component *component = ak4118->component;
265	struct snd_kcontrol_new *kctl_new;
 
 
266	unsigned int i;
267
268	if (!component)
269		return IRQ_NONE;
270
271	for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
272		kctl_new = &ak4118_iec958_controls[i];
273
274		snd_soc_component_notify_control(component, kctl_new->name);
 
 
 
 
 
275	}
276
277	return IRQ_HANDLED;
278}
279
280static int ak4118_probe(struct snd_soc_component *component)
281{
282	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
283	int ret = 0;
284
285	ak4118->component = component;
286
287	/* release reset */
288	gpiod_set_value(ak4118->reset, 0);
289
290	/* unmask all int1 sources */
291	ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
292	if (ret < 0) {
293		dev_err(component->dev,
294			"failed to write regmap 0x%x 0x%x: %d\n",
295			AK4118_REG_INT1_MASK, 0x00, ret);
296		return ret;
297	}
298
299	/* rx detect enable on all channels */
300	ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
301	if (ret < 0) {
302		dev_err(component->dev,
303			"failed to write regmap 0x%x 0x%x: %d\n",
304			AK4118_REG_RX_DETECT, 0xff, ret);
305		return ret;
306	}
307
308	ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
309					 ARRAY_SIZE(ak4118_iec958_controls));
310	if (ret) {
311		dev_err(component->dev,
312			"failed to add component kcontrols: %d\n", ret);
313		return ret;
314	}
315
316	return 0;
317}
318
319static void ak4118_remove(struct snd_soc_component *component)
320{
321	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
322
323	/* hold reset */
324	gpiod_set_value(ak4118->reset, 1);
325}
326
327static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
328	.probe			= ak4118_probe,
329	.remove			= ak4118_remove,
330	.dapm_widgets		= ak4118_dapm_widgets,
331	.num_dapm_widgets	= ARRAY_SIZE(ak4118_dapm_widgets),
332	.dapm_routes		= ak4118_dapm_routes,
333	.num_dapm_routes	= ARRAY_SIZE(ak4118_dapm_routes),
334	.idle_bias_on		= 1,
335	.use_pmdown_time	= 1,
336	.endianness		= 1,
 
337};
338
339static const struct regmap_config ak4118_regmap = {
340	.reg_bits = 8,
341	.val_bits = 8,
342
343	.reg_defaults = ak4118_reg_defaults,
344	.num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
345
346	.cache_type = REGCACHE_NONE,
347	.max_register = AK4118_REG_MAX - 1,
348};
349
350static int ak4118_i2c_probe(struct i2c_client *i2c)
 
351{
352	struct ak4118_priv *ak4118;
353	int ret;
354
355	ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
356			      GFP_KERNEL);
357	if (ak4118 == NULL)
358		return -ENOMEM;
359
360	ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
361	if (IS_ERR(ak4118->regmap))
362		return PTR_ERR(ak4118->regmap);
363
364	i2c_set_clientdata(i2c, ak4118);
365
366	ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
367	if (IS_ERR(ak4118->reset))
368		return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->reset),
369				     "Failed to get reset\n");
 
 
 
370
371	ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
372	if (IS_ERR(ak4118->irq))
373		return dev_err_probe(&i2c->dev, PTR_ERR(ak4118->irq),
374				     "Failed to get IRQ\n");
 
 
 
375
376	ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
377					NULL, ak4118_irq_handler,
378					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
379					"ak4118-irq", ak4118);
380	if (ret < 0) {
381		dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
382		return ret;
383	}
384
385	return devm_snd_soc_register_component(&i2c->dev,
386				&soc_component_drv_ak4118, &ak4118_dai, 1);
387}
388
389#ifdef CONFIG_OF
390static const struct of_device_id ak4118_of_match[] = {
391	{ .compatible = "asahi-kasei,ak4118", },
392	{}
393};
394MODULE_DEVICE_TABLE(of, ak4118_of_match);
395#endif
396
397static const struct i2c_device_id ak4118_id_table[] = {
398	{ "ak4118" },
399	{}
400};
401MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
402
403static struct i2c_driver ak4118_i2c_driver = {
404	.driver  = {
405		.name = "ak4118",
406		.of_match_table = of_match_ptr(ak4118_of_match),
407	},
408	.id_table = ak4118_id_table,
409	.probe = ak4118_i2c_probe,
410};
411
412module_i2c_driver(ak4118_i2c_driver);
413
414MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
415MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
416MODULE_LICENSE("GPL");
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * ak4118.c  --  Asahi Kasei ALSA Soc Audio driver
  4 *
  5 * Copyright 2018 DEVIALET
  6 */
  7
  8#include <linux/i2c.h>
  9#include <linux/gpio/consumer.h>
 10#include <linux/module.h>
 11#include <linux/of_device.h>
 12#include <linux/of_gpio.h>
 13#include <linux/regmap.h>
 14#include <linux/slab.h>
 15
 16#include <sound/asoundef.h>
 17#include <sound/core.h>
 18#include <sound/initval.h>
 19#include <sound/soc.h>
 20
 21#define AK4118_REG_CLK_PWR_CTL		0x00
 22#define AK4118_REG_FORMAT_CTL		0x01
 23#define AK4118_REG_IO_CTL0		0x02
 24#define AK4118_REG_IO_CTL1		0x03
 25#define AK4118_REG_INT0_MASK		0x04
 26#define AK4118_REG_INT1_MASK		0x05
 27#define AK4118_REG_RCV_STATUS0		0x06
 28#define AK4118_REG_RCV_STATUS1		0x07
 29#define AK4118_REG_RXCHAN_STATUS0	0x08
 30#define AK4118_REG_RXCHAN_STATUS1	0x09
 31#define AK4118_REG_RXCHAN_STATUS2	0x0a
 32#define AK4118_REG_RXCHAN_STATUS3	0x0b
 33#define AK4118_REG_RXCHAN_STATUS4	0x0c
 34#define AK4118_REG_TXCHAN_STATUS0	0x0d
 35#define AK4118_REG_TXCHAN_STATUS1	0x0e
 36#define AK4118_REG_TXCHAN_STATUS2	0x0f
 37#define AK4118_REG_TXCHAN_STATUS3	0x10
 38#define AK4118_REG_TXCHAN_STATUS4	0x11
 39#define AK4118_REG_BURST_PREAMB_PC0	0x12
 40#define AK4118_REG_BURST_PREAMB_PC1	0x13
 41#define AK4118_REG_BURST_PREAMB_PD0	0x14
 42#define AK4118_REG_BURST_PREAMB_PD1	0x15
 43#define AK4118_REG_QSUB_CTL		0x16
 44#define AK4118_REG_QSUB_TRACK		0x17
 45#define AK4118_REG_QSUB_INDEX		0x18
 46#define AK4118_REG_QSUB_MIN		0x19
 47#define AK4118_REG_QSUB_SEC		0x1a
 48#define AK4118_REG_QSUB_FRAME		0x1b
 49#define AK4118_REG_QSUB_ZERO		0x1c
 50#define AK4118_REG_QSUB_ABS_MIN		0x1d
 51#define AK4118_REG_QSUB_ABS_SEC		0x1e
 52#define AK4118_REG_QSUB_ABS_FRAME	0x1f
 53#define AK4118_REG_GPE			0x20
 54#define AK4118_REG_GPDR			0x21
 55#define AK4118_REG_GPSCR		0x22
 56#define AK4118_REG_GPLR			0x23
 57#define AK4118_REG_DAT_MASK_DTS		0x24
 58#define AK4118_REG_RX_DETECT		0x25
 59#define AK4118_REG_STC_DAT_DETECT	0x26
 60#define AK4118_REG_RXCHAN_STATUS5	0x27
 61#define AK4118_REG_TXCHAN_STATUS5	0x28
 62#define AK4118_REG_MAX			0x29
 63
 64#define AK4118_REG_FORMAT_CTL_DIF0	(1 << 4)
 65#define AK4118_REG_FORMAT_CTL_DIF1	(1 << 5)
 66#define AK4118_REG_FORMAT_CTL_DIF2	(1 << 6)
 67
 68struct ak4118_priv {
 69	struct regmap *regmap;
 70	struct gpio_desc *reset;
 71	struct gpio_desc *irq;
 72	struct snd_soc_component *component;
 73};
 74
 75static const struct reg_default ak4118_reg_defaults[] = {
 76	{AK4118_REG_CLK_PWR_CTL,	0x43},
 77	{AK4118_REG_FORMAT_CTL,		0x6a},
 78	{AK4118_REG_IO_CTL0,		0x88},
 79	{AK4118_REG_IO_CTL1,		0x48},
 80	{AK4118_REG_INT0_MASK,		0xee},
 81	{AK4118_REG_INT1_MASK,		0xb5},
 82	{AK4118_REG_RCV_STATUS0,	0x00},
 83	{AK4118_REG_RCV_STATUS1,	0x10},
 84	{AK4118_REG_TXCHAN_STATUS0,	0x00},
 85	{AK4118_REG_TXCHAN_STATUS1,	0x00},
 86	{AK4118_REG_TXCHAN_STATUS2,	0x00},
 87	{AK4118_REG_TXCHAN_STATUS3,	0x00},
 88	{AK4118_REG_TXCHAN_STATUS4,	0x00},
 89	{AK4118_REG_GPE,		0x77},
 90	{AK4118_REG_GPDR,		0x00},
 91	{AK4118_REG_GPSCR,		0x00},
 92	{AK4118_REG_GPLR,		0x00},
 93	{AK4118_REG_DAT_MASK_DTS,	0x3f},
 94	{AK4118_REG_RX_DETECT,		0x00},
 95	{AK4118_REG_STC_DAT_DETECT,	0x00},
 96	{AK4118_REG_TXCHAN_STATUS5,	0x00},
 97};
 98
 99static const char * const ak4118_input_select_txt[] = {
100	"RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7",
101};
102static SOC_ENUM_SINGLE_DECL(ak4118_insel_enum, AK4118_REG_IO_CTL1, 0x0,
103			    ak4118_input_select_txt);
104
105static const struct snd_kcontrol_new ak4118_input_mux_controls =
106	SOC_DAPM_ENUM("Input Select", ak4118_insel_enum);
107
108static const char * const ak4118_iec958_fs_txt[] = {
109	"44100", "48000", "32000", "22050", "11025", "24000", "16000", "88200",
110	"8000", "96000", "64000", "176400", "192000",
111};
112
113static const int ak4118_iec958_fs_val[] = {
114	0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xE,
115};
116
117static SOC_VALUE_ENUM_SINGLE_DECL(ak4118_iec958_fs_enum, AK4118_REG_RCV_STATUS1,
118				  0x4, 0x4, ak4118_iec958_fs_txt,
119				  ak4118_iec958_fs_val);
120
121static struct snd_kcontrol_new ak4118_iec958_controls[] = {
122	SOC_SINGLE("IEC958 Parity Errors", AK4118_REG_RCV_STATUS0, 0, 1, 0),
123	SOC_SINGLE("IEC958 No Audio", AK4118_REG_RCV_STATUS0, 1, 1, 0),
124	SOC_SINGLE("IEC958 PLL Lock", AK4118_REG_RCV_STATUS0, 4, 1, 1),
125	SOC_SINGLE("IEC958 Non PCM", AK4118_REG_RCV_STATUS0, 6, 1, 0),
126	SOC_ENUM("IEC958 Sampling Freq", ak4118_iec958_fs_enum),
127};
128
129static const struct snd_soc_dapm_widget ak4118_dapm_widgets[] = {
130	SND_SOC_DAPM_INPUT("INRX0"),
131	SND_SOC_DAPM_INPUT("INRX1"),
132	SND_SOC_DAPM_INPUT("INRX2"),
133	SND_SOC_DAPM_INPUT("INRX3"),
134	SND_SOC_DAPM_INPUT("INRX4"),
135	SND_SOC_DAPM_INPUT("INRX5"),
136	SND_SOC_DAPM_INPUT("INRX6"),
137	SND_SOC_DAPM_INPUT("INRX7"),
138	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
139			 &ak4118_input_mux_controls),
140};
141
142static const struct snd_soc_dapm_route ak4118_dapm_routes[] = {
143	{"Input Mux", "RX0", "INRX0"},
144	{"Input Mux", "RX1", "INRX1"},
145	{"Input Mux", "RX2", "INRX2"},
146	{"Input Mux", "RX3", "INRX3"},
147	{"Input Mux", "RX4", "INRX4"},
148	{"Input Mux", "RX5", "INRX5"},
149	{"Input Mux", "RX6", "INRX6"},
150	{"Input Mux", "RX7", "INRX7"},
151};
152
153
154static int ak4118_set_dai_fmt_master(struct ak4118_priv *ak4118,
155				     unsigned int format)
156{
157	int dif;
158
159	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
160	case SND_SOC_DAIFMT_I2S:
161		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF2;
162		break;
163	case SND_SOC_DAIFMT_RIGHT_J:
164		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1;
165		break;
166	case SND_SOC_DAIFMT_LEFT_J:
167		dif = AK4118_REG_FORMAT_CTL_DIF2;
168		break;
169	default:
170		return -ENOTSUPP;
171	}
172
173	return dif;
174}
175
176static int ak4118_set_dai_fmt_slave(struct ak4118_priv *ak4118,
177				    unsigned int format)
178{
179	int dif;
180
181	switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
182	case SND_SOC_DAIFMT_I2S:
183		dif = AK4118_REG_FORMAT_CTL_DIF0 | AK4118_REG_FORMAT_CTL_DIF1 |
184		      AK4118_REG_FORMAT_CTL_DIF2;
185		break;
186	case SND_SOC_DAIFMT_LEFT_J:
187		dif = AK4118_REG_FORMAT_CTL_DIF1 | AK4118_REG_FORMAT_CTL_DIF2;
188		break;
189	default:
190		return -ENOTSUPP;
191	}
192
193	return dif;
194}
195
196static int ak4118_set_dai_fmt(struct snd_soc_dai *dai,
197			      unsigned int format)
198{
199	struct snd_soc_component *component = dai->component;
200	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
201	int dif;
202	int ret = 0;
203
204	switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
205	case SND_SOC_DAIFMT_CBM_CFM:
206		/* component is master */
207		dif = ak4118_set_dai_fmt_master(ak4118, format);
208		break;
209	case SND_SOC_DAIFMT_CBS_CFS:
210		/*component is slave */
211		dif = ak4118_set_dai_fmt_slave(ak4118, format);
212		break;
213	default:
214		ret = -ENOTSUPP;
215		goto exit;
216	}
217
218	/* format not supported */
219	if (dif < 0) {
220		ret = dif;
221		goto exit;
222	}
223
224	ret = regmap_update_bits(ak4118->regmap, AK4118_REG_FORMAT_CTL,
225				 AK4118_REG_FORMAT_CTL_DIF0 |
226				 AK4118_REG_FORMAT_CTL_DIF1 |
227				 AK4118_REG_FORMAT_CTL_DIF2, dif);
228	if (ret < 0)
229		goto exit;
230
231exit:
232	return ret;
233}
234
235static int ak4118_hw_params(struct snd_pcm_substream *substream,
236			    struct snd_pcm_hw_params *params,
237			    struct snd_soc_dai *dai)
238{
239	return 0;
240}
241
242static const struct snd_soc_dai_ops ak4118_dai_ops = {
243	.hw_params = ak4118_hw_params,
244	.set_fmt   = ak4118_set_dai_fmt,
245};
246
247static struct snd_soc_dai_driver ak4118_dai = {
248	.name = "ak4118-hifi",
249	.capture = {
250		.stream_name = "Capture",
251		.channels_min = 2,
252		.channels_max = 2,
253		.rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
254			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
255			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
256			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
257		.formats = SNDRV_PCM_FMTBIT_S16_LE  |
258			   SNDRV_PCM_FMTBIT_S24_3LE |
259			   SNDRV_PCM_FMTBIT_S24_LE
260	},
261	.ops = &ak4118_dai_ops,
262};
263
264static irqreturn_t ak4118_irq_handler(int irq, void *data)
265{
266	struct ak4118_priv *ak4118 = data;
267	struct snd_soc_component *component = ak4118->component;
268	struct snd_kcontrol_new *kctl_new;
269	struct snd_kcontrol *kctl;
270	struct snd_ctl_elem_id *id;
271	unsigned int i;
272
273	if (!component)
274		return IRQ_NONE;
275
276	for (i = 0; i < ARRAY_SIZE(ak4118_iec958_controls); i++) {
277		kctl_new = &ak4118_iec958_controls[i];
278		kctl = snd_soc_card_get_kcontrol(component->card,
279						 kctl_new->name);
280		if (!kctl)
281			continue;
282		id = &kctl->id;
283		snd_ctl_notify(component->card->snd_card,
284			       SNDRV_CTL_EVENT_MASK_VALUE, id);
285	}
286
287	return IRQ_HANDLED;
288}
289
290static int ak4118_probe(struct snd_soc_component *component)
291{
292	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
293	int ret = 0;
294
295	ak4118->component = component;
296
297	/* release reset */
298	gpiod_set_value(ak4118->reset, 0);
299
300	/* unmask all int1 sources */
301	ret = regmap_write(ak4118->regmap, AK4118_REG_INT1_MASK, 0x00);
302	if (ret < 0) {
303		dev_err(component->dev,
304			"failed to write regmap 0x%x 0x%x: %d\n",
305			AK4118_REG_INT1_MASK, 0x00, ret);
306		return ret;
307	}
308
309	/* rx detect enable on all channels */
310	ret = regmap_write(ak4118->regmap, AK4118_REG_RX_DETECT, 0xff);
311	if (ret < 0) {
312		dev_err(component->dev,
313			"failed to write regmap 0x%x 0x%x: %d\n",
314			AK4118_REG_RX_DETECT, 0xff, ret);
315		return ret;
316	}
317
318	ret = snd_soc_add_component_controls(component, ak4118_iec958_controls,
319					 ARRAY_SIZE(ak4118_iec958_controls));
320	if (ret) {
321		dev_err(component->dev,
322			"failed to add component kcontrols: %d\n", ret);
323		return ret;
324	}
325
326	return 0;
327}
328
329static void ak4118_remove(struct snd_soc_component *component)
330{
331	struct ak4118_priv *ak4118 = snd_soc_component_get_drvdata(component);
332
333	/* hold reset */
334	gpiod_set_value(ak4118->reset, 1);
335}
336
337static const struct snd_soc_component_driver soc_component_drv_ak4118 = {
338	.probe			= ak4118_probe,
339	.remove			= ak4118_remove,
340	.dapm_widgets		= ak4118_dapm_widgets,
341	.num_dapm_widgets	= ARRAY_SIZE(ak4118_dapm_widgets),
342	.dapm_routes		= ak4118_dapm_routes,
343	.num_dapm_routes	= ARRAY_SIZE(ak4118_dapm_routes),
344	.idle_bias_on		= 1,
345	.use_pmdown_time	= 1,
346	.endianness		= 1,
347	.non_legacy_dai_naming	= 1,
348};
349
350static const struct regmap_config ak4118_regmap = {
351	.reg_bits = 8,
352	.val_bits = 8,
353
354	.reg_defaults = ak4118_reg_defaults,
355	.num_reg_defaults = ARRAY_SIZE(ak4118_reg_defaults),
356
357	.cache_type = REGCACHE_NONE,
358	.max_register = AK4118_REG_MAX - 1,
359};
360
361static int ak4118_i2c_probe(struct i2c_client *i2c,
362			    const struct i2c_device_id *id)
363{
364	struct ak4118_priv *ak4118;
365	int ret;
366
367	ak4118 = devm_kzalloc(&i2c->dev, sizeof(struct ak4118_priv),
368			      GFP_KERNEL);
369	if (ak4118 == NULL)
370		return -ENOMEM;
371
372	ak4118->regmap = devm_regmap_init_i2c(i2c, &ak4118_regmap);
373	if (IS_ERR(ak4118->regmap))
374		return PTR_ERR(ak4118->regmap);
375
376	i2c_set_clientdata(i2c, ak4118);
377
378	ak4118->reset = devm_gpiod_get(&i2c->dev, "reset", GPIOD_OUT_HIGH);
379	if (IS_ERR(ak4118->reset)) {
380		ret = PTR_ERR(ak4118->reset);
381		if (ret != -EPROBE_DEFER)
382			dev_err(&i2c->dev, "Failed to get reset: %d\n", ret);
383		return ret;
384	}
385
386	ak4118->irq = devm_gpiod_get(&i2c->dev, "irq", GPIOD_IN);
387	if (IS_ERR(ak4118->irq)) {
388		ret = PTR_ERR(ak4118->irq);
389		if (ret != -EPROBE_DEFER)
390			dev_err(&i2c->dev, "Failed to get IRQ: %d\n", ret);
391		return ret;
392	}
393
394	ret = devm_request_threaded_irq(&i2c->dev, gpiod_to_irq(ak4118->irq),
395					NULL, ak4118_irq_handler,
396					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
397					"ak4118-irq", ak4118);
398	if (ret < 0) {
399		dev_err(&i2c->dev, "Fail to request_irq: %d\n", ret);
400		return ret;
401	}
402
403	return devm_snd_soc_register_component(&i2c->dev,
404				&soc_component_drv_ak4118, &ak4118_dai, 1);
405}
406
 
407static const struct of_device_id ak4118_of_match[] = {
408	{ .compatible = "asahi-kasei,ak4118", },
409	{}
410};
411MODULE_DEVICE_TABLE(of, ak4118_of_match);
 
412
413static const struct i2c_device_id ak4118_id_table[] = {
414	{ "ak4118", 0 },
415	{}
416};
417MODULE_DEVICE_TABLE(i2c, ak4118_id_table);
418
419static struct i2c_driver ak4118_i2c_driver = {
420	.driver  = {
421		.name = "ak4118",
422		.of_match_table = of_match_ptr(ak4118_of_match),
423	},
424	.id_table = ak4118_id_table,
425	.probe  = ak4118_i2c_probe,
426};
427
428module_i2c_driver(ak4118_i2c_driver);
429
430MODULE_DESCRIPTION("Asahi Kasei AK4118 ALSA SoC driver");
431MODULE_AUTHOR("Adrien Charruel <adrien.charruel@devialet.com>");
432MODULE_LICENSE("GPL");