0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/init.h>
0013 #include <linux/delay.h>
0014 #include <linux/pm.h>
0015 #include <linux/i2c.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/regmap.h>
0018 #include <linux/spi/spi.h>
0019 #include <linux/slab.h>
0020 #include <linux/of_device.h>
0021 #include <sound/core.h>
0022 #include <sound/pcm.h>
0023 #include <sound/pcm_params.h>
0024 #include <sound/soc.h>
0025 #include <sound/initval.h>
0026 #include <sound/tlv.h>
0027
0028 #include "wm8728.h"
0029
0030
0031
0032
0033
0034
0035
0036 static const struct reg_default wm8728_reg_defaults[] = {
0037 { 0, 0x1ff },
0038 { 1, 0x1ff },
0039 { 2, 0x001 },
0040 { 3, 0x100 },
0041 };
0042
0043
0044 struct wm8728_priv {
0045 struct regmap *regmap;
0046 };
0047
0048 static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
0049
0050 static const struct snd_kcontrol_new wm8728_snd_controls[] = {
0051
0052 SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL,
0053 0, 255, 0, wm8728_tlv),
0054
0055 SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0),
0056 };
0057
0058
0059
0060
0061 static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = {
0062 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0),
0063 SND_SOC_DAPM_OUTPUT("VOUTL"),
0064 SND_SOC_DAPM_OUTPUT("VOUTR"),
0065 };
0066
0067 static const struct snd_soc_dapm_route wm8728_intercon[] = {
0068 {"VOUTL", NULL, "DAC"},
0069 {"VOUTR", NULL, "DAC"},
0070 };
0071
0072 static int wm8728_mute(struct snd_soc_dai *dai, int mute, int direction)
0073 {
0074 struct snd_soc_component *component = dai->component;
0075 u16 mute_reg = snd_soc_component_read(component, WM8728_DACCTL);
0076
0077 if (mute)
0078 snd_soc_component_write(component, WM8728_DACCTL, mute_reg | 1);
0079 else
0080 snd_soc_component_write(component, WM8728_DACCTL, mute_reg & ~1);
0081
0082 return 0;
0083 }
0084
0085 static int wm8728_hw_params(struct snd_pcm_substream *substream,
0086 struct snd_pcm_hw_params *params,
0087 struct snd_soc_dai *dai)
0088 {
0089 struct snd_soc_component *component = dai->component;
0090 u16 dac = snd_soc_component_read(component, WM8728_DACCTL);
0091
0092 dac &= ~0x18;
0093
0094 switch (params_width(params)) {
0095 case 16:
0096 break;
0097 case 20:
0098 dac |= 0x10;
0099 break;
0100 case 24:
0101 dac |= 0x08;
0102 break;
0103 default:
0104 return -EINVAL;
0105 }
0106
0107 snd_soc_component_write(component, WM8728_DACCTL, dac);
0108
0109 return 0;
0110 }
0111
0112 static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
0113 unsigned int fmt)
0114 {
0115 struct snd_soc_component *component = codec_dai->component;
0116 u16 iface = snd_soc_component_read(component, WM8728_IFCTL);
0117
0118
0119
0120
0121 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
0122 case SND_SOC_DAIFMT_I2S:
0123 iface |= 1;
0124 break;
0125 default:
0126 return -EINVAL;
0127 }
0128
0129
0130 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
0131 case SND_SOC_DAIFMT_CBS_CFS:
0132 break;
0133 default:
0134 return -EINVAL;
0135 }
0136
0137 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
0138 case SND_SOC_DAIFMT_NB_NF:
0139 iface &= ~0x22;
0140 break;
0141 case SND_SOC_DAIFMT_IB_NF:
0142 iface |= 0x20;
0143 iface &= ~0x02;
0144 break;
0145 case SND_SOC_DAIFMT_NB_IF:
0146 iface |= 0x02;
0147 iface &= ~0x20;
0148 break;
0149 case SND_SOC_DAIFMT_IB_IF:
0150 iface |= 0x22;
0151 break;
0152 default:
0153 return -EINVAL;
0154 }
0155
0156 snd_soc_component_write(component, WM8728_IFCTL, iface);
0157 return 0;
0158 }
0159
0160 static int wm8728_set_bias_level(struct snd_soc_component *component,
0161 enum snd_soc_bias_level level)
0162 {
0163 struct wm8728_priv *wm8728 = snd_soc_component_get_drvdata(component);
0164 u16 reg;
0165
0166 switch (level) {
0167 case SND_SOC_BIAS_ON:
0168 case SND_SOC_BIAS_PREPARE:
0169 case SND_SOC_BIAS_STANDBY:
0170 if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
0171
0172 reg = snd_soc_component_read(component, WM8728_DACCTL);
0173 snd_soc_component_write(component, WM8728_DACCTL, reg & ~0x4);
0174
0175
0176 regcache_sync(wm8728->regmap);
0177 }
0178 break;
0179
0180 case SND_SOC_BIAS_OFF:
0181 reg = snd_soc_component_read(component, WM8728_DACCTL);
0182 snd_soc_component_write(component, WM8728_DACCTL, reg | 0x4);
0183 break;
0184 }
0185 return 0;
0186 }
0187
0188 #define WM8728_RATES (SNDRV_PCM_RATE_8000_192000)
0189
0190 #define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
0191 SNDRV_PCM_FMTBIT_S24_LE)
0192
0193 static const struct snd_soc_dai_ops wm8728_dai_ops = {
0194 .hw_params = wm8728_hw_params,
0195 .mute_stream = wm8728_mute,
0196 .set_fmt = wm8728_set_dai_fmt,
0197 .no_capture_mute = 1,
0198 };
0199
0200 static struct snd_soc_dai_driver wm8728_dai = {
0201 .name = "wm8728-hifi",
0202 .playback = {
0203 .stream_name = "Playback",
0204 .channels_min = 2,
0205 .channels_max = 2,
0206 .rates = WM8728_RATES,
0207 .formats = WM8728_FORMATS,
0208 },
0209 .ops = &wm8728_dai_ops,
0210 };
0211
0212 static const struct snd_soc_component_driver soc_component_dev_wm8728 = {
0213 .set_bias_level = wm8728_set_bias_level,
0214 .controls = wm8728_snd_controls,
0215 .num_controls = ARRAY_SIZE(wm8728_snd_controls),
0216 .dapm_widgets = wm8728_dapm_widgets,
0217 .num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets),
0218 .dapm_routes = wm8728_intercon,
0219 .num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
0220 .suspend_bias_off = 1,
0221 .idle_bias_on = 1,
0222 .use_pmdown_time = 1,
0223 .endianness = 1,
0224 };
0225
0226 static const struct of_device_id wm8728_of_match[] = {
0227 { .compatible = "wlf,wm8728", },
0228 { }
0229 };
0230 MODULE_DEVICE_TABLE(of, wm8728_of_match);
0231
0232 static const struct regmap_config wm8728_regmap = {
0233 .reg_bits = 7,
0234 .val_bits = 9,
0235 .max_register = WM8728_IFCTL,
0236
0237 .reg_defaults = wm8728_reg_defaults,
0238 .num_reg_defaults = ARRAY_SIZE(wm8728_reg_defaults),
0239 .cache_type = REGCACHE_RBTREE,
0240 };
0241
0242 #if defined(CONFIG_SPI_MASTER)
0243 static int wm8728_spi_probe(struct spi_device *spi)
0244 {
0245 struct wm8728_priv *wm8728;
0246 int ret;
0247
0248 wm8728 = devm_kzalloc(&spi->dev, sizeof(struct wm8728_priv),
0249 GFP_KERNEL);
0250 if (wm8728 == NULL)
0251 return -ENOMEM;
0252
0253 wm8728->regmap = devm_regmap_init_spi(spi, &wm8728_regmap);
0254 if (IS_ERR(wm8728->regmap))
0255 return PTR_ERR(wm8728->regmap);
0256
0257 spi_set_drvdata(spi, wm8728);
0258
0259 ret = devm_snd_soc_register_component(&spi->dev,
0260 &soc_component_dev_wm8728, &wm8728_dai, 1);
0261
0262 return ret;
0263 }
0264
0265 static struct spi_driver wm8728_spi_driver = {
0266 .driver = {
0267 .name = "wm8728",
0268 .of_match_table = wm8728_of_match,
0269 },
0270 .probe = wm8728_spi_probe,
0271 };
0272 #endif
0273
0274 #if IS_ENABLED(CONFIG_I2C)
0275 static int wm8728_i2c_probe(struct i2c_client *i2c)
0276 {
0277 struct wm8728_priv *wm8728;
0278 int ret;
0279
0280 wm8728 = devm_kzalloc(&i2c->dev, sizeof(struct wm8728_priv),
0281 GFP_KERNEL);
0282 if (wm8728 == NULL)
0283 return -ENOMEM;
0284
0285 wm8728->regmap = devm_regmap_init_i2c(i2c, &wm8728_regmap);
0286 if (IS_ERR(wm8728->regmap))
0287 return PTR_ERR(wm8728->regmap);
0288
0289 i2c_set_clientdata(i2c, wm8728);
0290
0291 ret = devm_snd_soc_register_component(&i2c->dev,
0292 &soc_component_dev_wm8728, &wm8728_dai, 1);
0293
0294 return ret;
0295 }
0296
0297 static const struct i2c_device_id wm8728_i2c_id[] = {
0298 { "wm8728", 0 },
0299 { }
0300 };
0301 MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
0302
0303 static struct i2c_driver wm8728_i2c_driver = {
0304 .driver = {
0305 .name = "wm8728",
0306 .of_match_table = wm8728_of_match,
0307 },
0308 .probe_new = wm8728_i2c_probe,
0309 .id_table = wm8728_i2c_id,
0310 };
0311 #endif
0312
0313 static int __init wm8728_modinit(void)
0314 {
0315 int ret = 0;
0316 #if IS_ENABLED(CONFIG_I2C)
0317 ret = i2c_add_driver(&wm8728_i2c_driver);
0318 if (ret != 0) {
0319 printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
0320 ret);
0321 }
0322 #endif
0323 #if defined(CONFIG_SPI_MASTER)
0324 ret = spi_register_driver(&wm8728_spi_driver);
0325 if (ret != 0) {
0326 printk(KERN_ERR "Failed to register wm8728 SPI driver: %d\n",
0327 ret);
0328 }
0329 #endif
0330 return ret;
0331 }
0332 module_init(wm8728_modinit);
0333
0334 static void __exit wm8728_exit(void)
0335 {
0336 #if IS_ENABLED(CONFIG_I2C)
0337 i2c_del_driver(&wm8728_i2c_driver);
0338 #endif
0339 #if defined(CONFIG_SPI_MASTER)
0340 spi_unregister_driver(&wm8728_spi_driver);
0341 #endif
0342 }
0343 module_exit(wm8728_exit);
0344
0345 MODULE_DESCRIPTION("ASoC WM8728 driver");
0346 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
0347 MODULE_LICENSE("GPL");