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