brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · 61f4a38 Raw
257 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Analog Devices ADV7511 HDMI transmitter driver4 *5 * Copyright 2012 Analog Devices Inc.6 * Copyright (c) 2016, Linaro Limited7 */8 9#include <sound/core.h>10#include <sound/hdmi-codec.h>11#include <sound/pcm.h>12#include <sound/soc.h>13#include <linux/of_graph.h>14 15#include "adv7511.h"16 17static void adv7511_calc_cts_n(unsigned int f_tmds, unsigned int fs,18			       unsigned int *cts, unsigned int *n)19{20	switch (fs) {21	case 32000:22	case 48000:23	case 96000:24	case 192000:25		*n = fs * 128 / 1000;26		break;27	case 44100:28	case 88200:29	case 176400:30		*n = fs * 128 / 900;31		break;32	}33 34	*cts = ((f_tmds * *n) / (128 * fs)) * 1000;35}36 37static int adv7511_update_cts_n(struct adv7511 *adv7511)38{39	unsigned int cts = 0;40	unsigned int n = 0;41 42	adv7511_calc_cts_n(adv7511->f_tmds, adv7511->f_audio, &cts, &n);43 44	regmap_write(adv7511->regmap, ADV7511_REG_N0, (n >> 16) & 0xf);45	regmap_write(adv7511->regmap, ADV7511_REG_N1, (n >> 8) & 0xff);46	regmap_write(adv7511->regmap, ADV7511_REG_N2, n & 0xff);47 48	regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL0,49		     (cts >> 16) & 0xf);50	regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL1,51		     (cts >> 8) & 0xff);52	regmap_write(adv7511->regmap, ADV7511_REG_CTS_MANUAL2,53		     cts & 0xff);54 55	return 0;56}57 58static int adv7511_hdmi_hw_params(struct device *dev, void *data,59				  struct hdmi_codec_daifmt *fmt,60				  struct hdmi_codec_params *hparms)61{62	struct adv7511 *adv7511 = dev_get_drvdata(dev);63	unsigned int audio_source, i2s_format = 0;64	unsigned int invert_clock;65	unsigned int rate;66	unsigned int len;67 68	switch (hparms->sample_rate) {69	case 32000:70		rate = ADV7511_SAMPLE_FREQ_32000;71		break;72	case 44100:73		rate = ADV7511_SAMPLE_FREQ_44100;74		break;75	case 48000:76		rate = ADV7511_SAMPLE_FREQ_48000;77		break;78	case 88200:79		rate = ADV7511_SAMPLE_FREQ_88200;80		break;81	case 96000:82		rate = ADV7511_SAMPLE_FREQ_96000;83		break;84	case 176400:85		rate = ADV7511_SAMPLE_FREQ_176400;86		break;87	case 192000:88		rate = ADV7511_SAMPLE_FREQ_192000;89		break;90	default:91		return -EINVAL;92	}93 94	switch (hparms->sample_width) {95	case 16:96		len = ADV7511_I2S_SAMPLE_LEN_16;97		break;98	case 18:99		len = ADV7511_I2S_SAMPLE_LEN_18;100		break;101	case 20:102		len = ADV7511_I2S_SAMPLE_LEN_20;103		break;104	case 32:105		if (fmt->bit_fmt != SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)106			return -EINVAL;107		fallthrough;108	case 24:109		len = ADV7511_I2S_SAMPLE_LEN_24;110		break;111	default:112		return -EINVAL;113	}114 115	switch (fmt->fmt) {116	case HDMI_I2S:117		audio_source = ADV7511_AUDIO_SOURCE_I2S;118		i2s_format = ADV7511_I2S_FORMAT_I2S;119		if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)120			i2s_format = ADV7511_I2S_IEC958_DIRECT;121		break;122	case HDMI_RIGHT_J:123		audio_source = ADV7511_AUDIO_SOURCE_I2S;124		i2s_format = ADV7511_I2S_FORMAT_RIGHT_J;125		break;126	case HDMI_LEFT_J:127		audio_source = ADV7511_AUDIO_SOURCE_I2S;128		i2s_format = ADV7511_I2S_FORMAT_LEFT_J;129		break;130	case HDMI_SPDIF:131		audio_source = ADV7511_AUDIO_SOURCE_SPDIF;132		break;133	default:134		return -EINVAL;135	}136 137	invert_clock = fmt->bit_clk_inv;138 139	regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_SOURCE, 0x70,140			   audio_source << 4);141	regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG, BIT(6),142			   invert_clock << 6);143	regmap_update_bits(adv7511->regmap, ADV7511_REG_I2S_CONFIG, 0x03,144			   i2s_format);145 146	adv7511->audio_source = audio_source;147 148	adv7511->f_audio = hparms->sample_rate;149 150	adv7511_update_cts_n(adv7511);151 152	regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG3,153			   ADV7511_AUDIO_CFG3_LEN_MASK, len);154	regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG,155			   ADV7511_I2C_FREQ_ID_CFG_RATE_MASK, rate << 4);156	regmap_write(adv7511->regmap, 0x73, 0x1);157 158	return 0;159}160 161static int audio_startup(struct device *dev, void *data)162{163	struct adv7511 *adv7511 = dev_get_drvdata(dev);164 165	regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,166				BIT(7), 0);167 168	/* hide Audio infoframe updates */169	regmap_update_bits(adv7511->regmap, ADV7511_REG_INFOFRAME_UPDATE,170				BIT(5), BIT(5));171	/* enable N/CTS, enable Audio sample packets */172	regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,173				BIT(5), BIT(5));174	/* enable N/CTS */175	regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,176				BIT(6), BIT(6));177	/* not copyrighted */178	regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CFG1,179				BIT(5), BIT(5));180	/* enable audio infoframes */181	regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1,182				BIT(3), BIT(3));183	/* AV mute disable */184	regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(0),185				BIT(7) | BIT(6), BIT(7));186	/* use Audio infoframe updated info */187	regmap_update_bits(adv7511->regmap, ADV7511_REG_GC(1),188				BIT(5), 0);189	/* enable SPDIF receiver */190	if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)191		regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,192				   BIT(7), BIT(7));193 194	return 0;195}196 197static void audio_shutdown(struct device *dev, void *data)198{199	struct adv7511 *adv7511 = dev_get_drvdata(dev);200 201	if (adv7511->audio_source == ADV7511_AUDIO_SOURCE_SPDIF)202		regmap_update_bits(adv7511->regmap, ADV7511_REG_AUDIO_CONFIG,203				   BIT(7), 0);204}205 206static int adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component *component,207					struct device_node *endpoint)208{209	struct of_endpoint of_ep;210	int ret;211 212	ret = of_graph_parse_endpoint(endpoint, &of_ep);213	if (ret < 0)214		return ret;215 216	/*217	 * HDMI sound should be located as reg = <2>218	 * Then, it is sound port 0219	 */220	if (of_ep.port == 2)221		return 0;222 223	return -EINVAL;224}225 226static const struct hdmi_codec_ops adv7511_codec_ops = {227	.hw_params	= adv7511_hdmi_hw_params,228	.audio_shutdown = audio_shutdown,229	.audio_startup	= audio_startup,230	.get_dai_id	= adv7511_hdmi_i2s_get_dai_id,231};232 233static const struct hdmi_codec_pdata codec_data = {234	.ops = &adv7511_codec_ops,235	.max_i2s_channels = 2,236	.i2s = 1,237	.spdif = 1,238};239 240int adv7511_audio_init(struct device *dev, struct adv7511 *adv7511)241{242	adv7511->audio_pdev = platform_device_register_data(dev,243					HDMI_CODEC_DRV_NAME,244					PLATFORM_DEVID_AUTO,245					&codec_data,246					sizeof(codec_data));247	return PTR_ERR_OR_ZERO(adv7511->audio_pdev);248}249 250void adv7511_audio_exit(struct adv7511 *adv7511)251{252	if (adv7511->audio_pdev) {253		platform_device_unregister(adv7511->audio_pdev);254		adv7511->audio_pdev = NULL;255	}256}257