0001
0002
0003
0004
0005
0006 #include <linux/gpio/consumer.h>
0007 #include <linux/module.h>
0008 #include <linux/workqueue.h>
0009
0010 #include <sound/pcm_params.h>
0011 #include <sound/soc.h>
0012 #include <sound/tlv.h>
0013
0014 #include "pcm1789.h"
0015
0016 #define PCM1789_MUTE_CONTROL 0x10
0017 #define PCM1789_FMT_CONTROL 0x11
0018 #define PCM1789_SOFT_MUTE 0x14
0019 #define PCM1789_DAC_VOL_LEFT 0x18
0020 #define PCM1789_DAC_VOL_RIGHT 0x19
0021
0022 #define PCM1789_FMT_MASK 0x07
0023 #define PCM1789_MUTE_MASK 0x03
0024 #define PCM1789_MUTE_SRET 0x06
0025
0026 struct pcm1789_private {
0027 struct regmap *regmap;
0028 unsigned int format;
0029 unsigned int rate;
0030 struct gpio_desc *reset;
0031 struct work_struct work;
0032 struct device *dev;
0033 };
0034
0035 static const struct reg_default pcm1789_reg_defaults[] = {
0036 { PCM1789_FMT_CONTROL, 0x00 },
0037 { PCM1789_SOFT_MUTE, 0x00 },
0038 { PCM1789_DAC_VOL_LEFT, 0xff },
0039 { PCM1789_DAC_VOL_RIGHT, 0xff },
0040 };
0041
0042 static bool pcm1789_accessible_reg(struct device *dev, unsigned int reg)
0043 {
0044 return reg >= PCM1789_MUTE_CONTROL && reg <= PCM1789_DAC_VOL_RIGHT;
0045 }
0046
0047 static bool pcm1789_writeable_reg(struct device *dev, unsigned int reg)
0048 {
0049 return pcm1789_accessible_reg(dev, reg);
0050 }
0051
0052 static int pcm1789_set_dai_fmt(struct snd_soc_dai *codec_dai,
0053 unsigned int format)
0054 {
0055 struct snd_soc_component *component = codec_dai->component;
0056 struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
0057
0058 priv->format = format;
0059
0060 return 0;
0061 }
0062
0063 static int pcm1789_mute(struct snd_soc_dai *codec_dai, int mute, int direction)
0064 {
0065 struct snd_soc_component *component = codec_dai->component;
0066 struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
0067
0068 return regmap_update_bits(priv->regmap, PCM1789_SOFT_MUTE,
0069 PCM1789_MUTE_MASK,
0070 mute ? 0 : PCM1789_MUTE_MASK);
0071 }
0072
0073 static int pcm1789_hw_params(struct snd_pcm_substream *substream,
0074 struct snd_pcm_hw_params *params,
0075 struct snd_soc_dai *codec_dai)
0076 {
0077 struct snd_soc_component *component = codec_dai->component;
0078 struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
0079 int val = 0, ret;
0080
0081 priv->rate = params_rate(params);
0082
0083 switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
0084 case SND_SOC_DAIFMT_RIGHT_J:
0085 switch (params_width(params)) {
0086 case 24:
0087 val = 2;
0088 break;
0089 case 16:
0090 val = 3;
0091 break;
0092 default:
0093 return -EINVAL;
0094 }
0095 break;
0096 case SND_SOC_DAIFMT_I2S:
0097 switch (params_width(params)) {
0098 case 16:
0099 case 24:
0100 case 32:
0101 val = 0;
0102 break;
0103 default:
0104 return -EINVAL;
0105 }
0106 break;
0107 case SND_SOC_DAIFMT_LEFT_J:
0108 switch (params_width(params)) {
0109 case 16:
0110 case 24:
0111 case 32:
0112 val = 1;
0113 break;
0114 default:
0115 return -EINVAL;
0116 }
0117 break;
0118 default:
0119 dev_err(component->dev, "Invalid DAI format\n");
0120 return -EINVAL;
0121 }
0122
0123 ret = regmap_update_bits(priv->regmap, PCM1789_FMT_CONTROL,
0124 PCM1789_FMT_MASK, val);
0125 if (ret < 0)
0126 return ret;
0127
0128 return 0;
0129 }
0130
0131 static void pcm1789_work_queue(struct work_struct *work)
0132 {
0133 struct pcm1789_private *priv = container_of(work,
0134 struct pcm1789_private,
0135 work);
0136
0137
0138 if (regmap_update_bits(priv->regmap, PCM1789_MUTE_CONTROL,
0139 0x3 << PCM1789_MUTE_SRET, 0) < 0)
0140 dev_err(priv->dev, "Error while setting SRET");
0141 }
0142
0143 static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd,
0144 struct snd_soc_dai *dai)
0145 {
0146 struct snd_soc_component *component = dai->component;
0147 struct pcm1789_private *priv = snd_soc_component_get_drvdata(component);
0148 int ret = 0;
0149
0150 switch (cmd) {
0151 case SNDRV_PCM_TRIGGER_START:
0152 case SNDRV_PCM_TRIGGER_RESUME:
0153 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0154 schedule_work(&priv->work);
0155 break;
0156 case SNDRV_PCM_TRIGGER_STOP:
0157 case SNDRV_PCM_TRIGGER_SUSPEND:
0158 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0159 break;
0160 default:
0161 ret = -EINVAL;
0162 }
0163
0164 return ret;
0165 }
0166
0167 static const struct snd_soc_dai_ops pcm1789_dai_ops = {
0168 .set_fmt = pcm1789_set_dai_fmt,
0169 .hw_params = pcm1789_hw_params,
0170 .mute_stream = pcm1789_mute,
0171 .trigger = pcm1789_trigger,
0172 .no_capture_mute = 1,
0173 };
0174
0175 static const DECLARE_TLV_DB_SCALE(pcm1789_dac_tlv, -12000, 50, 1);
0176
0177 static const struct snd_kcontrol_new pcm1789_controls[] = {
0178 SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1789_DAC_VOL_LEFT,
0179 PCM1789_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
0180 pcm1789_dac_tlv),
0181 };
0182
0183 static const struct snd_soc_dapm_widget pcm1789_dapm_widgets[] = {
0184 SND_SOC_DAPM_OUTPUT("IOUTL+"),
0185 SND_SOC_DAPM_OUTPUT("IOUTL-"),
0186 SND_SOC_DAPM_OUTPUT("IOUTR+"),
0187 SND_SOC_DAPM_OUTPUT("IOUTR-"),
0188 };
0189
0190 static const struct snd_soc_dapm_route pcm1789_dapm_routes[] = {
0191 { "IOUTL+", NULL, "Playback" },
0192 { "IOUTL-", NULL, "Playback" },
0193 { "IOUTR+", NULL, "Playback" },
0194 { "IOUTR-", NULL, "Playback" },
0195 };
0196
0197 static struct snd_soc_dai_driver pcm1789_dai = {
0198 .name = "pcm1789-hifi",
0199 .playback = {
0200 .stream_name = "Playback",
0201 .channels_min = 2,
0202 .channels_max = 2,
0203 .rates = SNDRV_PCM_RATE_CONTINUOUS,
0204 .rate_min = 10000,
0205 .rate_max = 200000,
0206 .formats = PCM1789_FORMATS,
0207 },
0208 .ops = &pcm1789_dai_ops,
0209 };
0210
0211 const struct regmap_config pcm1789_regmap_config = {
0212 .reg_bits = 8,
0213 .val_bits = 8,
0214 .max_register = PCM1789_DAC_VOL_RIGHT,
0215 .reg_defaults = pcm1789_reg_defaults,
0216 .num_reg_defaults = ARRAY_SIZE(pcm1789_reg_defaults),
0217 .writeable_reg = pcm1789_writeable_reg,
0218 .readable_reg = pcm1789_accessible_reg,
0219 };
0220 EXPORT_SYMBOL_GPL(pcm1789_regmap_config);
0221
0222 static const struct snd_soc_component_driver soc_component_dev_pcm1789 = {
0223 .controls = pcm1789_controls,
0224 .num_controls = ARRAY_SIZE(pcm1789_controls),
0225 .dapm_widgets = pcm1789_dapm_widgets,
0226 .num_dapm_widgets = ARRAY_SIZE(pcm1789_dapm_widgets),
0227 .dapm_routes = pcm1789_dapm_routes,
0228 .num_dapm_routes = ARRAY_SIZE(pcm1789_dapm_routes),
0229 .idle_bias_on = 1,
0230 .use_pmdown_time = 1,
0231 .endianness = 1,
0232 };
0233
0234 int pcm1789_common_init(struct device *dev, struct regmap *regmap)
0235 {
0236 struct pcm1789_private *pcm1789;
0237
0238 pcm1789 = devm_kzalloc(dev, sizeof(struct pcm1789_private),
0239 GFP_KERNEL);
0240 if (!pcm1789)
0241 return -ENOMEM;
0242
0243 pcm1789->regmap = regmap;
0244 pcm1789->dev = dev;
0245 dev_set_drvdata(dev, pcm1789);
0246
0247 pcm1789->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
0248 if (IS_ERR(pcm1789->reset))
0249 return PTR_ERR(pcm1789->reset);
0250
0251 gpiod_set_value_cansleep(pcm1789->reset, 0);
0252 msleep(300);
0253
0254 INIT_WORK(&pcm1789->work, pcm1789_work_queue);
0255
0256 return devm_snd_soc_register_component(dev, &soc_component_dev_pcm1789,
0257 &pcm1789_dai, 1);
0258 }
0259 EXPORT_SYMBOL_GPL(pcm1789_common_init);
0260
0261 void pcm1789_common_exit(struct device *dev)
0262 {
0263 struct pcm1789_private *priv = dev_get_drvdata(dev);
0264
0265 flush_work(&priv->work);
0266 }
0267 EXPORT_SYMBOL_GPL(pcm1789_common_exit);
0268
0269 MODULE_DESCRIPTION("ASoC PCM1789 driver");
0270 MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
0271 MODULE_LICENSE("GPL");