Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: Add PCM1792A spi mode codec support

Add PCM1792A spi mode codec support. This version implements only
a subset of functionalities. Tested connect to a pandaboard ES
device and based on recently pcm1681 codec.

Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Michael Trimarchi and committed by
Mark Brown
13b02fa0 c095ba72

+295
+18
Documentation/devicetree/bindings/sound/pcm1792a.txt
··· 1 + Texas Instruments pcm1792a DT bindings 2 + 3 + This driver supports the SPI bus. 4 + 5 + Required properties: 6 + 7 + - compatible: "ti,pcm1792a" 8 + 9 + For required properties on SPI, please consult 10 + Documentation/devicetree/bindings/spi/spi-bus.txt 11 + 12 + Examples: 13 + 14 + codec_spi: 1792a@0 { 15 + compatible = "ti,pcm1792a"; 16 + spi-max-frequency = <600000>; 17 + }; 18 +
+4
sound/soc/codecs/Kconfig
··· 54 54 select SND_SOC_MC13783 if MFD_MC13XXX 55 55 select SND_SOC_ML26124 if I2C 56 56 select SND_SOC_HDMI_CODEC 57 + select SND_SOC_PCM1792A if SPI_MASTER 57 58 select SND_SOC_PCM3008 58 59 select SND_SOC_RT5631 if I2C 59 60 select SND_SOC_RT5640 if I2C ··· 291 290 tristate 292 291 293 292 config SND_SOC_HDMI_CODEC 293 + tristate 294 + 295 + config SND_SOC_PCM1792A 294 296 tristate 295 297 296 298 config SND_SOC_PCM3008
+2
sound/soc/codecs/Makefile
··· 42 42 snd-soc-mc13783-objs := mc13783.o 43 43 snd-soc-ml26124-objs := ml26124.o 44 44 snd-soc-hdmi-codec-objs := hdmi.o 45 + snd-soc-pcm1792a-codec-objs := pcm1792a.o 45 46 snd-soc-pcm3008-objs := pcm3008.o 46 47 snd-soc-rt5631-objs := rt5631.o 47 48 snd-soc-rt5640-objs := rt5640.o ··· 172 171 obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o 173 172 obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o 174 173 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o 174 + obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o 175 175 obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 176 176 obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o 177 177 obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
+245
sound/soc/codecs/pcm1792a.c
··· 1 + /* 2 + * PCM1792A ASoC codec driver 3 + * 4 + * Copyright (c) Amarula Solutions B.V. 2013 5 + * 6 + * Michael Trimarchi <michael@amarulasolutions.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * as published by the Free Software Foundation; either version 2 11 + * of the License, or (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + */ 18 + 19 + #include <linux/module.h> 20 + #include <linux/slab.h> 21 + #include <linux/kernel.h> 22 + #include <linux/device.h> 23 + #include <linux/spi/spi.h> 24 + 25 + #include <sound/core.h> 26 + #include <sound/pcm.h> 27 + #include <sound/pcm_params.h> 28 + #include <sound/initval.h> 29 + #include <sound/soc.h> 30 + #include <sound/tlv.h> 31 + #include <linux/of_device.h> 32 + 33 + #include "pcm1792a.h" 34 + 35 + #define PCM1792A_DAC_VOL_LEFT 0x10 36 + #define PCM1792A_DAC_VOL_RIGHT 0x11 37 + #define PCM1792A_FMT_CONTROL 0x12 38 + #define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL 39 + 40 + #define PCM1792A_FMT_MASK 0x70 41 + #define PCM1792A_FMT_SHIFT 4 42 + #define PCM1792A_MUTE_MASK 0x01 43 + #define PCM1792A_MUTE_SHIFT 0 44 + #define PCM1792A_ATLD_ENABLE (1 << 7) 45 + 46 + static const struct reg_default pcm1792a_reg_defaults[] = { 47 + { 0x10, 0xff }, 48 + { 0x11, 0xff }, 49 + { 0x12, 0x50 }, 50 + { 0x13, 0x00 }, 51 + { 0x14, 0x00 }, 52 + { 0x15, 0x01 }, 53 + { 0x16, 0x00 }, 54 + { 0x17, 0x00 }, 55 + }; 56 + 57 + static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg) 58 + { 59 + return reg >= 0x10 && reg <= 0x17; 60 + } 61 + 62 + static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg) 63 + { 64 + bool accessible; 65 + 66 + accessible = pcm1792a_accessible_reg(dev, reg); 67 + 68 + return accessible && reg != 0x16 && reg != 0x17; 69 + } 70 + 71 + struct pcm1792a_private { 72 + struct regmap *regmap; 73 + unsigned int format; 74 + unsigned int rate; 75 + }; 76 + 77 + static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai, 78 + unsigned int format) 79 + { 80 + struct snd_soc_codec *codec = codec_dai->codec; 81 + struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); 82 + 83 + priv->format = format; 84 + 85 + return 0; 86 + } 87 + 88 + static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute) 89 + { 90 + struct snd_soc_codec *codec = dai->codec; 91 + struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); 92 + int ret; 93 + 94 + ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE, 95 + PCM1792A_MUTE_MASK, !!mute); 96 + if (ret < 0) 97 + return ret; 98 + 99 + return 0; 100 + } 101 + 102 + static int pcm1792a_hw_params(struct snd_pcm_substream *substream, 103 + struct snd_pcm_hw_params *params, 104 + struct snd_soc_dai *dai) 105 + { 106 + struct snd_soc_codec *codec = dai->codec; 107 + struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); 108 + int val = 0, ret; 109 + int pcm_format = params_format(params); 110 + 111 + priv->rate = params_rate(params); 112 + 113 + switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { 114 + case SND_SOC_DAIFMT_RIGHT_J: 115 + if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || 116 + pcm_format == SNDRV_PCM_FORMAT_S32_LE) 117 + val = 0x02; 118 + else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) 119 + val = 0x00; 120 + break; 121 + case SND_SOC_DAIFMT_I2S: 122 + if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || 123 + pcm_format == SNDRV_PCM_FORMAT_S32_LE) 124 + val = 0x05; 125 + else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) 126 + val = 0x04; 127 + break; 128 + default: 129 + dev_err(codec->dev, "Invalid DAI format\n"); 130 + return -EINVAL; 131 + } 132 + 133 + val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE; 134 + 135 + ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL, 136 + PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val); 137 + if (ret < 0) 138 + return ret; 139 + 140 + return 0; 141 + } 142 + 143 + static const struct snd_soc_dai_ops pcm1792a_dai_ops = { 144 + .set_fmt = pcm1792a_set_dai_fmt, 145 + .hw_params = pcm1792a_hw_params, 146 + .digital_mute = pcm1792a_digital_mute, 147 + }; 148 + 149 + static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1); 150 + 151 + static const struct snd_kcontrol_new pcm1792a_controls[] = { 152 + SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT, 153 + PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, 154 + pcm1792a_dac_tlv), 155 + }; 156 + 157 + static struct snd_soc_dai_driver pcm1792a_dai = { 158 + .name = "pcm1792a-hifi", 159 + .playback = { 160 + .stream_name = "Playback", 161 + .channels_min = 2, 162 + .channels_max = 2, 163 + .rates = PCM1792A_RATES, 164 + .formats = PCM1792A_FORMATS, }, 165 + .capture = { 166 + .channels_min = 0, 167 + .channels_max = 0, 168 + }, 169 + .ops = &pcm1792a_dai_ops, 170 + }; 171 + 172 + #ifdef CONFIG_OF 173 + static const struct of_device_id pcm1792a_of_match[] = { 174 + { .compatible = "ti,pcm1792a", }, 175 + { } 176 + }; 177 + MODULE_DEVICE_TABLE(of, pcm1792a_of_match); 178 + #endif 179 + 180 + static const struct regmap_config pcm1792a_regmap = { 181 + .reg_bits = 8, 182 + .val_bits = 8, 183 + .max_register = 24, 184 + .reg_defaults = pcm1792a_reg_defaults, 185 + .num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults), 186 + .writeable_reg = pcm1792a_writeable_reg, 187 + .readable_reg = pcm1792a_accessible_reg, 188 + }; 189 + 190 + static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = { 191 + .controls = pcm1792a_controls, 192 + .num_controls = ARRAY_SIZE(pcm1792a_controls), 193 + }; 194 + 195 + static int pcm1792a_spi_probe(struct spi_device *spi) 196 + { 197 + struct pcm1792a_private *pcm1792a; 198 + int ret; 199 + 200 + pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private), 201 + GFP_KERNEL); 202 + if (!pcm1792a) 203 + return -ENOMEM; 204 + 205 + spi_set_drvdata(spi, pcm1792a); 206 + 207 + pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap); 208 + if (IS_ERR(pcm1792a->regmap)) { 209 + ret = PTR_ERR(pcm1792a->regmap); 210 + dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); 211 + return ret; 212 + } 213 + 214 + return snd_soc_register_codec(&spi->dev, 215 + &soc_codec_dev_pcm1792a, &pcm1792a_dai, 1); 216 + } 217 + 218 + static int pcm1792a_spi_remove(struct spi_device *spi) 219 + { 220 + snd_soc_unregister_codec(&spi->dev); 221 + return 0; 222 + } 223 + 224 + static const struct spi_device_id pcm1792a_spi_ids[] = { 225 + { "pcm1792a", 0 }, 226 + { }, 227 + }; 228 + MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids); 229 + 230 + static struct spi_driver pcm1792a_codec_driver = { 231 + .driver = { 232 + .name = "pcm1792a", 233 + .owner = THIS_MODULE, 234 + .of_match_table = pcm1792a_of_match, 235 + }, 236 + .id_table = pcm1792a_spi_ids, 237 + .probe = pcm1792a_spi_probe, 238 + .remove = pcm1792a_spi_remove, 239 + }; 240 + 241 + module_spi_driver(pcm1792a_codec_driver); 242 + 243 + MODULE_DESCRIPTION("ASoC PCM1792A driver"); 244 + MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>"); 245 + MODULE_LICENSE("GPL");
+26
sound/soc/codecs/pcm1792a.h
··· 1 + /* 2 + * definitions for PCM1792A 3 + * 4 + * Copyright 2013 Amarula Solutions 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 2 9 + * of the License, or (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + */ 16 + 17 + #ifndef __PCM1792A_H__ 18 + #define __PCM1792A_H__ 19 + 20 + #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ 21 + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) 22 + 23 + #define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \ 24 + SNDRV_PCM_FMTBIT_S16_LE) 25 + 26 + #endif