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

ASoC: Add ADAU1977 CODEC driver

This patch adds support for the ADAU1977, ADAU1978 and ADAU1979 audio CODEC
devices. They are a family of 4-channel differential input audio ADC devices.
They can be connected to either a SPI or I2C bus. The driver is implemented in
three modules, one main module (adau1977.ko) which implements the device logic
and one module each for SPI (adau1977-spi.ko) and I2C (adau1977-i2c.ko) bus
access.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Lars-Peter Clausen and committed by
Mark Brown
603597c9 a32eb702

+1256
+45
include/linux/platform_data/adau1977.h
··· 1 + /* 2 + * ADAU1977/ADAU1978/ADAU1979 driver 3 + * 4 + * Copyright 2014 Analog Devices Inc. 5 + * Author: Lars-Peter Clausen <lars@metafoo.de> 6 + * 7 + * Licensed under the GPL-2. 8 + */ 9 + 10 + #ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__ 11 + #define __LINUX_PLATFORM_DATA_ADAU1977_H__ 12 + 13 + /** 14 + * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting 15 + * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V 16 + * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V 17 + * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V 18 + * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V 19 + * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V 20 + * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V 21 + * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V 22 + * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V 23 + * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V 24 + */ 25 + enum adau1977_micbias { 26 + ADAU1977_MICBIAS_5V0 = 0x0, 27 + ADAU1977_MICBIAS_5V5 = 0x1, 28 + ADAU1977_MICBIAS_6V0 = 0x2, 29 + ADAU1977_MICBIAS_6V5 = 0x3, 30 + ADAU1977_MICBIAS_7V0 = 0x4, 31 + ADAU1977_MICBIAS_7V5 = 0x5, 32 + ADAU1977_MICBIAS_8V0 = 0x6, 33 + ADAU1977_MICBIAS_8V5 = 0x7, 34 + ADAU1977_MICBIAS_9V0 = 0x8, 35 + }; 36 + 37 + /** 38 + * struct adau1977_platform_data - Platform configuration data for the ADAU1977 39 + * @micbias: Specifies the voltage for the MICBIAS pin 40 + */ 41 + struct adau1977_platform_data { 42 + enum adau1977_micbias micbias; 43 + }; 44 + 45 + #endif
+15
sound/soc/codecs/Kconfig
··· 24 24 select SND_SOC_ADAU1373 if I2C 25 25 select SND_SOC_ADAV801 if SPI_MASTER 26 26 select SND_SOC_ADAV803 if I2C 27 + select SND_SOC_ADAU1977_SPI if SPI_MASTER 28 + select SND_SOC_ADAU1977_I2C if I2C 27 29 select SND_SOC_ADAU1701 if I2C 28 30 select SND_SOC_ADS117X 29 31 select SND_SOC_AK4104 if SPI_MASTER ··· 201 199 202 200 config SND_SOC_ADAU1373 203 201 tristate 202 + 203 + config SND_SOC_ADAU1977 204 + tristate 205 + 206 + config SND_SOC_ADAU1977_SPI 207 + tristate 208 + select SND_SOC_ADAU1977 209 + select REGMAP_SPI 210 + 211 + config SND_SOC_ADAU1977_I2C 212 + tristate 213 + select SND_SOC_ADAU1977 214 + select REGMAP_I2C 204 215 205 216 config SND_SOC_ADAV80X 206 217 tristate
+6
sound/soc/codecs/Makefile
··· 7 7 snd-soc-ad73311-objs := ad73311.o 8 8 snd-soc-adau1701-objs := adau1701.o 9 9 snd-soc-adau1373-objs := adau1373.o 10 + snd-soc-adau1977-objs := adau1977.o 11 + snd-soc-adau1977-spi-objs := adau1977-spi.o 12 + snd-soc-adau1977-i2c-objs := adau1977-i2c.o 10 13 snd-soc-adav80x-objs := adav80x.o 11 14 snd-soc-adav801-objs := adav801.o 12 15 snd-soc-adav803-objs := adav803.o ··· 142 139 obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o 143 140 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o 144 141 obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o 142 + obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o 143 + obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o 144 + obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o 145 145 obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o 146 146 obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o 147 147 obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o
+59
sound/soc/codecs/adau1977-i2c.c
··· 1 + /* 2 + * ADAU1977/ADAU1978/ADAU1979 driver 3 + * 4 + * Copyright 2014 Analog Devices Inc. 5 + * Author: Lars-Peter Clausen <lars@metafoo.de> 6 + * 7 + * Licensed under the GPL-2. 8 + */ 9 + 10 + #include <linux/i2c.h> 11 + #include <linux/mod_devicetable.h> 12 + #include <linux/module.h> 13 + #include <linux/regmap.h> 14 + #include <sound/soc.h> 15 + 16 + #include "adau1977.h" 17 + 18 + static int adau1977_i2c_probe(struct i2c_client *client, 19 + const struct i2c_device_id *id) 20 + { 21 + struct regmap_config config; 22 + 23 + config = adau1977_regmap_config; 24 + config.val_bits = 8; 25 + config.reg_bits = 8; 26 + 27 + return adau1977_probe(&client->dev, 28 + devm_regmap_init_i2c(client, &config), 29 + id->driver_data, NULL); 30 + } 31 + 32 + static int adau1977_i2c_remove(struct i2c_client *client) 33 + { 34 + snd_soc_unregister_codec(&client->dev); 35 + return 0; 36 + } 37 + 38 + static const struct i2c_device_id adau1977_i2c_ids[] = { 39 + { "adau1977", ADAU1977 }, 40 + { "adau1978", ADAU1978 }, 41 + { "adau1979", ADAU1978 }, 42 + { } 43 + }; 44 + MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); 45 + 46 + static struct i2c_driver adau1977_i2c_driver = { 47 + .driver = { 48 + .name = "adau1977", 49 + .owner = THIS_MODULE, 50 + }, 51 + .probe = adau1977_i2c_probe, 52 + .remove = adau1977_i2c_remove, 53 + .id_table = adau1977_i2c_ids, 54 + }; 55 + module_i2c_driver(adau1977_i2c_driver); 56 + 57 + MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); 58 + MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 59 + MODULE_LICENSE("GPL");
+76
sound/soc/codecs/adau1977-spi.c
··· 1 + /* 2 + * ADAU1977/ADAU1978/ADAU1979 driver 3 + * 4 + * Copyright 2014 Analog Devices Inc. 5 + * Author: Lars-Peter Clausen <lars@metafoo.de> 6 + * 7 + * Licensed under the GPL-2. 8 + */ 9 + 10 + #include <linux/mod_devicetable.h> 11 + #include <linux/module.h> 12 + #include <linux/regmap.h> 13 + #include <linux/spi/spi.h> 14 + #include <sound/soc.h> 15 + 16 + #include "adau1977.h" 17 + 18 + static void adau1977_spi_switch_mode(struct device *dev) 19 + { 20 + struct spi_device *spi = to_spi_device(dev); 21 + 22 + /* 23 + * To get the device into SPI mode CLATCH has to be pulled low three 24 + * times. Do this by issuing three dummy reads. 25 + */ 26 + spi_w8r8(spi, 0x00); 27 + spi_w8r8(spi, 0x00); 28 + spi_w8r8(spi, 0x00); 29 + } 30 + 31 + static int adau1977_spi_probe(struct spi_device *spi) 32 + { 33 + const struct spi_device_id *id = spi_get_device_id(spi); 34 + struct regmap_config config; 35 + 36 + if (!id) 37 + return -EINVAL; 38 + 39 + config = adau1977_regmap_config; 40 + config.val_bits = 8; 41 + config.reg_bits = 16; 42 + config.read_flag_mask = 0x1; 43 + 44 + return adau1977_probe(&spi->dev, 45 + devm_regmap_init_spi(spi, &config), 46 + id->driver_data, adau1977_spi_switch_mode); 47 + } 48 + 49 + static int adau1977_spi_remove(struct spi_device *spi) 50 + { 51 + snd_soc_unregister_codec(&spi->dev); 52 + return 0; 53 + } 54 + 55 + static const struct spi_device_id adau1977_spi_ids[] = { 56 + { "adau1977", ADAU1977 }, 57 + { "adau1978", ADAU1978 }, 58 + { "adau1979", ADAU1978 }, 59 + { } 60 + }; 61 + MODULE_DEVICE_TABLE(spi, adau1977_spi_ids); 62 + 63 + static struct spi_driver adau1977_spi_driver = { 64 + .driver = { 65 + .name = "adau1977", 66 + .owner = THIS_MODULE, 67 + }, 68 + .probe = adau1977_spi_probe, 69 + .remove = adau1977_spi_remove, 70 + .id_table = adau1977_spi_ids, 71 + }; 72 + module_spi_driver(adau1977_spi_driver); 73 + 74 + MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); 75 + MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 76 + MODULE_LICENSE("GPL");
+1018
sound/soc/codecs/adau1977.c
··· 1 + /* 2 + * ADAU1977/ADAU1978/ADAU1979 driver 3 + * 4 + * Copyright 2014 Analog Devices Inc. 5 + * Author: Lars-Peter Clausen <lars@metafoo.de> 6 + * 7 + * Licensed under the GPL-2. 8 + */ 9 + 10 + #include <linux/delay.h> 11 + #include <linux/device.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/i2c.h> 14 + #include <linux/init.h> 15 + #include <linux/module.h> 16 + #include <linux/platform_data/adau1977.h> 17 + #include <linux/regmap.h> 18 + #include <linux/regulator/consumer.h> 19 + #include <linux/slab.h> 20 + 21 + #include <sound/core.h> 22 + #include <sound/initval.h> 23 + #include <sound/pcm.h> 24 + #include <sound/pcm_params.h> 25 + #include <sound/soc.h> 26 + #include <sound/tlv.h> 27 + 28 + #include "adau1977.h" 29 + 30 + #define ADAU1977_REG_POWER 0x00 31 + #define ADAU1977_REG_PLL 0x01 32 + #define ADAU1977_REG_BOOST 0x02 33 + #define ADAU1977_REG_MICBIAS 0x03 34 + #define ADAU1977_REG_BLOCK_POWER_SAI 0x04 35 + #define ADAU1977_REG_SAI_CTRL0 0x05 36 + #define ADAU1977_REG_SAI_CTRL1 0x06 37 + #define ADAU1977_REG_CMAP12 0x07 38 + #define ADAU1977_REG_CMAP34 0x08 39 + #define ADAU1977_REG_SAI_OVERTEMP 0x09 40 + #define ADAU1977_REG_POST_ADC_GAIN(x) (0x0a + (x)) 41 + #define ADAU1977_REG_MISC_CONTROL 0x0e 42 + #define ADAU1977_REG_DIAG_CONTROL 0x10 43 + #define ADAU1977_REG_STATUS(x) (0x11 + (x)) 44 + #define ADAU1977_REG_DIAG_IRQ1 0x15 45 + #define ADAU1977_REG_DIAG_IRQ2 0x16 46 + #define ADAU1977_REG_ADJUST1 0x17 47 + #define ADAU1977_REG_ADJUST2 0x18 48 + #define ADAU1977_REG_ADC_CLIP 0x19 49 + #define ADAU1977_REG_DC_HPF_CAL 0x1a 50 + 51 + #define ADAU1977_POWER_RESET BIT(7) 52 + #define ADAU1977_POWER_PWUP BIT(0) 53 + 54 + #define ADAU1977_PLL_CLK_S BIT(4) 55 + #define ADAU1977_PLL_MCS_MASK 0x7 56 + 57 + #define ADAU1977_MICBIAS_MB_VOLTS_MASK 0xf0 58 + #define ADAU1977_MICBIAS_MB_VOLTS_OFFSET 4 59 + 60 + #define ADAU1977_BLOCK_POWER_SAI_LR_POL BIT(7) 61 + #define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE BIT(6) 62 + #define ADAU1977_BLOCK_POWER_SAI_LDO_EN BIT(5) 63 + 64 + #define ADAU1977_SAI_CTRL0_FMT_MASK (0x3 << 6) 65 + #define ADAU1977_SAI_CTRL0_FMT_I2S (0x0 << 6) 66 + #define ADAU1977_SAI_CTRL0_FMT_LJ (0x1 << 6) 67 + #define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT (0x2 << 6) 68 + #define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT (0x3 << 6) 69 + 70 + #define ADAU1977_SAI_CTRL0_SAI_MASK (0x7 << 3) 71 + #define ADAU1977_SAI_CTRL0_SAI_I2S (0x0 << 3) 72 + #define ADAU1977_SAI_CTRL0_SAI_TDM_2 (0x1 << 3) 73 + #define ADAU1977_SAI_CTRL0_SAI_TDM_4 (0x2 << 3) 74 + #define ADAU1977_SAI_CTRL0_SAI_TDM_8 (0x3 << 3) 75 + #define ADAU1977_SAI_CTRL0_SAI_TDM_16 (0x4 << 3) 76 + 77 + #define ADAU1977_SAI_CTRL0_FS_MASK (0x7) 78 + #define ADAU1977_SAI_CTRL0_FS_8000_12000 (0x0) 79 + #define ADAU1977_SAI_CTRL0_FS_16000_24000 (0x1) 80 + #define ADAU1977_SAI_CTRL0_FS_32000_48000 (0x2) 81 + #define ADAU1977_SAI_CTRL0_FS_64000_96000 (0x3) 82 + #define ADAU1977_SAI_CTRL0_FS_128000_192000 (0x4) 83 + 84 + #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK (0x3 << 5) 85 + #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32 (0x0 << 5) 86 + #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24 (0x1 << 5) 87 + #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16 (0x2 << 5) 88 + #define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK (0x1 << 4) 89 + #define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT (0x1 << 4) 90 + #define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT (0x0 << 4) 91 + #define ADAU1977_SAI_CTRL1_LRCLK_PULSE BIT(3) 92 + #define ADAU1977_SAI_CTRL1_MSB BIT(2) 93 + #define ADAU1977_SAI_CTRL1_BCLKRATE_16 (0x1 << 1) 94 + #define ADAU1977_SAI_CTRL1_BCLKRATE_32 (0x0 << 1) 95 + #define ADAU1977_SAI_CTRL1_BCLKRATE_MASK (0x1 << 1) 96 + #define ADAU1977_SAI_CTRL1_MASTER BIT(0) 97 + 98 + #define ADAU1977_SAI_OVERTEMP_DRV_C(x) BIT(4 + (x)) 99 + #define ADAU1977_SAI_OVERTEMP_DRV_HIZ BIT(3) 100 + 101 + #define ADAU1977_MISC_CONTROL_SUM_MODE_MASK (0x3 << 6) 102 + #define ADAU1977_MISC_CONTROL_SUM_MODE_1CH (0x2 << 6) 103 + #define ADAU1977_MISC_CONTROL_SUM_MODE_2CH (0x1 << 6) 104 + #define ADAU1977_MISC_CONTROL_SUM_MODE_4CH (0x0 << 6) 105 + #define ADAU1977_MISC_CONTROL_MMUTE BIT(4) 106 + #define ADAU1977_MISC_CONTROL_DC_CAL BIT(0) 107 + 108 + #define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET 4 109 + #define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET 0 110 + 111 + struct adau1977 { 112 + struct regmap *regmap; 113 + bool right_j; 114 + unsigned int sysclk; 115 + enum adau1977_sysclk_src sysclk_src; 116 + struct gpio_desc *reset_gpio; 117 + enum adau1977_type type; 118 + 119 + struct regulator *avdd_reg; 120 + struct regulator *dvdd_reg; 121 + 122 + struct snd_pcm_hw_constraint_list constraints; 123 + 124 + struct device *dev; 125 + void (*switch_mode)(struct device *dev); 126 + 127 + unsigned int max_master_fs; 128 + unsigned int slot_width; 129 + bool enabled; 130 + bool master; 131 + }; 132 + 133 + static const struct reg_default adau1977_reg_defaults[] = { 134 + { 0x00, 0x00 }, 135 + { 0x01, 0x41 }, 136 + { 0x02, 0x4a }, 137 + { 0x03, 0x7d }, 138 + { 0x04, 0x3d }, 139 + { 0x05, 0x02 }, 140 + { 0x06, 0x00 }, 141 + { 0x07, 0x10 }, 142 + { 0x08, 0x32 }, 143 + { 0x09, 0xf0 }, 144 + { 0x0a, 0xa0 }, 145 + { 0x0b, 0xa0 }, 146 + { 0x0c, 0xa0 }, 147 + { 0x0d, 0xa0 }, 148 + { 0x0e, 0x02 }, 149 + { 0x10, 0x0f }, 150 + { 0x15, 0x20 }, 151 + { 0x16, 0x00 }, 152 + { 0x17, 0x00 }, 153 + { 0x18, 0x00 }, 154 + { 0x1a, 0x00 }, 155 + }; 156 + 157 + static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000); 158 + 159 + static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = { 160 + SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS, 161 + 3, 0, NULL, 0) 162 + }; 163 + 164 + static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = { 165 + SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI, 166 + 4, 0, NULL, 0), 167 + 168 + SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0), 169 + SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0), 170 + SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0), 171 + SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0), 172 + 173 + SND_SOC_DAPM_INPUT("AIN1"), 174 + SND_SOC_DAPM_INPUT("AIN2"), 175 + SND_SOC_DAPM_INPUT("AIN3"), 176 + SND_SOC_DAPM_INPUT("AIN4"), 177 + 178 + SND_SOC_DAPM_OUTPUT("VREF"), 179 + }; 180 + 181 + static const struct snd_soc_dapm_route adau1977_dapm_routes[] = { 182 + { "ADC1", NULL, "AIN1" }, 183 + { "ADC2", NULL, "AIN2" }, 184 + { "ADC3", NULL, "AIN3" }, 185 + { "ADC4", NULL, "AIN4" }, 186 + 187 + { "ADC1", NULL, "Vref" }, 188 + { "ADC2", NULL, "Vref" }, 189 + { "ADC3", NULL, "Vref" }, 190 + { "ADC4", NULL, "Vref" }, 191 + 192 + { "VREF", NULL, "Vref" }, 193 + }; 194 + 195 + #define ADAU1977_VOLUME(x) \ 196 + SOC_SINGLE_TLV("ADC" #x " Capture Volume", \ 197 + ADAU1977_REG_POST_ADC_GAIN((x) - 1), \ 198 + 0, 255, 1, adau1977_adc_gain) 199 + 200 + #define ADAU1977_HPF_SWITCH(x) \ 201 + SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \ 202 + ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) 203 + 204 + #define ADAU1977_DC_SUB_SWITCH(x) \ 205 + SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \ 206 + ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) 207 + 208 + static const struct snd_kcontrol_new adau1977_snd_controls[] = { 209 + ADAU1977_VOLUME(1), 210 + ADAU1977_VOLUME(2), 211 + ADAU1977_VOLUME(3), 212 + ADAU1977_VOLUME(4), 213 + 214 + ADAU1977_HPF_SWITCH(1), 215 + ADAU1977_HPF_SWITCH(2), 216 + ADAU1977_HPF_SWITCH(3), 217 + ADAU1977_HPF_SWITCH(4), 218 + 219 + ADAU1977_DC_SUB_SWITCH(1), 220 + ADAU1977_DC_SUB_SWITCH(2), 221 + ADAU1977_DC_SUB_SWITCH(3), 222 + ADAU1977_DC_SUB_SWITCH(4), 223 + }; 224 + 225 + static int adau1977_reset(struct adau1977 *adau1977) 226 + { 227 + int ret; 228 + 229 + /* 230 + * The reset bit is obviously volatile, but we need to be able to cache 231 + * the other bits in the register, so we can't just mark the whole 232 + * register as volatile. Since this is the only place where we'll ever 233 + * touch the reset bit just bypass the cache for this operation. 234 + */ 235 + regcache_cache_bypass(adau1977->regmap, true); 236 + ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER, 237 + ADAU1977_POWER_RESET); 238 + regcache_cache_bypass(adau1977->regmap, false); 239 + if (ret) 240 + return ret; 241 + 242 + return ret; 243 + } 244 + 245 + /* 246 + * Returns the appropriate setting for ths FS field in the CTRL0 register 247 + * depending on the rate. 248 + */ 249 + static int adau1977_lookup_fs(unsigned int rate) 250 + { 251 + if (rate >= 8000 && rate <= 12000) 252 + return ADAU1977_SAI_CTRL0_FS_8000_12000; 253 + else if (rate >= 16000 && rate <= 24000) 254 + return ADAU1977_SAI_CTRL0_FS_16000_24000; 255 + else if (rate >= 32000 && rate <= 48000) 256 + return ADAU1977_SAI_CTRL0_FS_32000_48000; 257 + else if (rate >= 64000 && rate <= 96000) 258 + return ADAU1977_SAI_CTRL0_FS_64000_96000; 259 + else if (rate >= 128000 && rate <= 192000) 260 + return ADAU1977_SAI_CTRL0_FS_128000_192000; 261 + else 262 + return -EINVAL; 263 + } 264 + 265 + static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate, 266 + unsigned int fs) 267 + { 268 + unsigned int mcs; 269 + 270 + /* 271 + * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs 272 + * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs 273 + * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate) 274 + */ 275 + 276 + rate *= 512 >> fs; 277 + 278 + if (adau1977->sysclk % rate != 0) 279 + return -EINVAL; 280 + 281 + mcs = adau1977->sysclk / rate; 282 + 283 + /* The factors configured by MCS are 1, 2, 3, 4, 6 */ 284 + if (mcs < 1 || mcs > 6 || mcs == 5) 285 + return -EINVAL; 286 + 287 + mcs = mcs - 1; 288 + if (mcs == 5) 289 + mcs = 4; 290 + 291 + return mcs; 292 + } 293 + 294 + static int adau1977_hw_params(struct snd_pcm_substream *substream, 295 + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 296 + { 297 + struct snd_soc_codec *codec = dai->codec; 298 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); 299 + unsigned int rate = params_rate(params); 300 + unsigned int slot_width; 301 + unsigned int ctrl0, ctrl0_mask; 302 + unsigned int ctrl1; 303 + int mcs, fs; 304 + int ret; 305 + 306 + fs = adau1977_lookup_fs(rate); 307 + if (fs < 0) 308 + return fs; 309 + 310 + if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) { 311 + mcs = adau1977_lookup_mcs(adau1977, rate, fs); 312 + if (mcs < 0) 313 + return mcs; 314 + } else { 315 + mcs = 0; 316 + } 317 + 318 + ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK; 319 + ctrl0 = fs; 320 + 321 + if (adau1977->right_j) { 322 + switch (params_width(params)) { 323 + case 16: 324 + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT; 325 + break; 326 + case 24: 327 + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; 328 + break; 329 + default: 330 + return -EINVAL; 331 + } 332 + ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK; 333 + } 334 + 335 + if (adau1977->master) { 336 + switch (params_width(params)) { 337 + case 16: 338 + ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT; 339 + slot_width = 16; 340 + break; 341 + case 24: 342 + case 32: 343 + ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT; 344 + slot_width = 32; 345 + break; 346 + default: 347 + return -EINVAL; 348 + } 349 + 350 + /* In TDM mode there is a fixed slot width */ 351 + if (adau1977->slot_width) 352 + slot_width = adau1977->slot_width; 353 + 354 + if (slot_width == 16) 355 + ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16; 356 + else 357 + ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32; 358 + 359 + ret = regmap_update_bits(adau1977->regmap, 360 + ADAU1977_REG_SAI_CTRL1, 361 + ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK | 362 + ADAU1977_SAI_CTRL1_BCLKRATE_MASK, 363 + ctrl1); 364 + if (ret < 0) 365 + return ret; 366 + } 367 + 368 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, 369 + ctrl0_mask, ctrl0); 370 + if (ret < 0) 371 + return ret; 372 + 373 + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, 374 + ADAU1977_PLL_MCS_MASK, mcs); 375 + } 376 + 377 + static int adau1977_power_disable(struct adau1977 *adau1977) 378 + { 379 + int ret = 0; 380 + 381 + if (!adau1977->enabled) 382 + return 0; 383 + 384 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, 385 + ADAU1977_POWER_PWUP, 0); 386 + if (ret) 387 + return ret; 388 + 389 + regcache_mark_dirty(adau1977->regmap); 390 + 391 + if (adau1977->reset_gpio) 392 + gpiod_set_value_cansleep(adau1977->reset_gpio, 0); 393 + 394 + regcache_cache_only(adau1977->regmap, true); 395 + 396 + regulator_disable(adau1977->avdd_reg); 397 + if (adau1977->dvdd_reg) 398 + regulator_disable(adau1977->dvdd_reg); 399 + 400 + adau1977->enabled = false; 401 + 402 + return 0; 403 + } 404 + 405 + static int adau1977_power_enable(struct adau1977 *adau1977) 406 + { 407 + unsigned int val; 408 + int ret = 0; 409 + 410 + if (adau1977->enabled) 411 + return 0; 412 + 413 + ret = regulator_enable(adau1977->avdd_reg); 414 + if (ret) 415 + return ret; 416 + 417 + if (adau1977->dvdd_reg) { 418 + ret = regulator_enable(adau1977->dvdd_reg); 419 + if (ret) 420 + goto err_disable_avdd; 421 + } 422 + 423 + if (adau1977->reset_gpio) 424 + gpiod_set_value_cansleep(adau1977->reset_gpio, 1); 425 + 426 + regcache_cache_only(adau1977->regmap, false); 427 + 428 + if (adau1977->switch_mode) 429 + adau1977->switch_mode(adau1977->dev); 430 + 431 + ret = adau1977_reset(adau1977); 432 + if (ret) 433 + goto err_disable_dvdd; 434 + 435 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, 436 + ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP); 437 + if (ret) 438 + goto err_disable_dvdd; 439 + 440 + ret = regcache_sync(adau1977->regmap); 441 + if (ret) 442 + goto err_disable_dvdd; 443 + 444 + /* 445 + * The PLL register is not affected by the software reset. It is 446 + * possible that the value of the register was changed to the 447 + * default value while we were in cache only mode. In this case 448 + * regcache_sync will skip over it and we have to manually sync 449 + * it. 450 + */ 451 + ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val); 452 + if (ret) 453 + goto err_disable_dvdd; 454 + 455 + if (val == 0x41) { 456 + regcache_cache_bypass(adau1977->regmap, true); 457 + ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL, 458 + 0x41); 459 + if (ret) 460 + goto err_disable_dvdd; 461 + regcache_cache_bypass(adau1977->regmap, false); 462 + } 463 + 464 + adau1977->enabled = true; 465 + 466 + return ret; 467 + 468 + err_disable_dvdd: 469 + if (adau1977->dvdd_reg) 470 + regulator_disable(adau1977->dvdd_reg); 471 + err_disable_avdd: 472 + regulator_disable(adau1977->avdd_reg); 473 + return ret; 474 + } 475 + 476 + static int adau1977_set_bias_level(struct snd_soc_codec *codec, 477 + enum snd_soc_bias_level level) 478 + { 479 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); 480 + int ret = 0; 481 + 482 + switch (level) { 483 + case SND_SOC_BIAS_ON: 484 + break; 485 + case SND_SOC_BIAS_PREPARE: 486 + break; 487 + case SND_SOC_BIAS_STANDBY: 488 + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) 489 + ret = adau1977_power_enable(adau1977); 490 + break; 491 + case SND_SOC_BIAS_OFF: 492 + ret = adau1977_power_disable(adau1977); 493 + break; 494 + } 495 + 496 + if (ret) 497 + return ret; 498 + 499 + codec->dapm.bias_level = level; 500 + 501 + return 0; 502 + } 503 + 504 + static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 505 + unsigned int rx_mask, int slots, int width) 506 + { 507 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); 508 + unsigned int ctrl0, ctrl1, drv; 509 + unsigned int slot[4]; 510 + unsigned int i; 511 + int ret; 512 + 513 + if (slots == 0) { 514 + /* 0 = No fixed slot width */ 515 + adau1977->slot_width = 0; 516 + adau1977->max_master_fs = 192000; 517 + return regmap_update_bits(adau1977->regmap, 518 + ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK, 519 + ADAU1977_SAI_CTRL0_SAI_I2S); 520 + } 521 + 522 + if (rx_mask == 0 || tx_mask != 0) 523 + return -EINVAL; 524 + 525 + drv = 0; 526 + for (i = 0; i < 4; i++) { 527 + slot[i] = __ffs(rx_mask); 528 + drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i); 529 + rx_mask &= ~(1 << slot[i]); 530 + if (slot[i] >= slots) 531 + return -EINVAL; 532 + if (rx_mask == 0) 533 + break; 534 + } 535 + 536 + if (rx_mask != 0) 537 + return -EINVAL; 538 + 539 + switch (width) { 540 + case 16: 541 + ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16; 542 + break; 543 + case 24: 544 + /* We can only generate 16 bit or 32 bit wide slots */ 545 + if (adau1977->master) 546 + return -EINVAL; 547 + ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24; 548 + break; 549 + case 32: 550 + ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32; 551 + break; 552 + default: 553 + return -EINVAL; 554 + } 555 + 556 + switch (slots) { 557 + case 2: 558 + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2; 559 + break; 560 + case 4: 561 + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4; 562 + break; 563 + case 8: 564 + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8; 565 + break; 566 + case 16: 567 + ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16; 568 + break; 569 + default: 570 + return -EINVAL; 571 + } 572 + 573 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, 574 + ADAU1977_SAI_OVERTEMP_DRV_C(0) | 575 + ADAU1977_SAI_OVERTEMP_DRV_C(1) | 576 + ADAU1977_SAI_OVERTEMP_DRV_C(2) | 577 + ADAU1977_SAI_OVERTEMP_DRV_C(3), drv); 578 + if (ret) 579 + return ret; 580 + 581 + ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12, 582 + (slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | 583 + (slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); 584 + if (ret) 585 + return ret; 586 + 587 + ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34, 588 + (slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | 589 + (slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); 590 + if (ret) 591 + return ret; 592 + 593 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, 594 + ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0); 595 + if (ret) 596 + return ret; 597 + 598 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, 599 + ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1); 600 + if (ret) 601 + return ret; 602 + 603 + adau1977->slot_width = width; 604 + 605 + /* In master mode the maximum bitclock is 24.576 MHz */ 606 + adau1977->max_master_fs = min(192000, 24576000 / width / slots); 607 + 608 + return 0; 609 + } 610 + 611 + static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream) 612 + { 613 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); 614 + unsigned int val; 615 + 616 + if (mute) 617 + val = ADAU1977_MISC_CONTROL_MMUTE; 618 + else 619 + val = 0; 620 + 621 + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL, 622 + ADAU1977_MISC_CONTROL_MMUTE, val); 623 + } 624 + 625 + static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) 626 + { 627 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); 628 + unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0; 629 + bool invert_lrclk; 630 + int ret; 631 + 632 + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 633 + case SND_SOC_DAIFMT_CBS_CFS: 634 + adau1977->master = false; 635 + break; 636 + case SND_SOC_DAIFMT_CBM_CFM: 637 + ctrl1 |= ADAU1977_SAI_CTRL1_MASTER; 638 + adau1977->master = true; 639 + break; 640 + default: 641 + return -EINVAL; 642 + } 643 + 644 + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 645 + case SND_SOC_DAIFMT_NB_NF: 646 + invert_lrclk = false; 647 + break; 648 + case SND_SOC_DAIFMT_IB_NF: 649 + block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; 650 + invert_lrclk = false; 651 + break; 652 + case SND_SOC_DAIFMT_NB_IF: 653 + invert_lrclk = true; 654 + break; 655 + case SND_SOC_DAIFMT_IB_IF: 656 + block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; 657 + invert_lrclk = true; 658 + break; 659 + default: 660 + return -EINVAL; 661 + } 662 + 663 + adau1977->right_j = false; 664 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 665 + case SND_SOC_DAIFMT_I2S: 666 + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; 667 + break; 668 + case SND_SOC_DAIFMT_LEFT_J: 669 + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; 670 + invert_lrclk = !invert_lrclk; 671 + break; 672 + case SND_SOC_DAIFMT_RIGHT_J: 673 + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; 674 + adau1977->right_j = true; 675 + invert_lrclk = !invert_lrclk; 676 + break; 677 + case SND_SOC_DAIFMT_DSP_A: 678 + ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; 679 + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; 680 + invert_lrclk = false; 681 + break; 682 + case SND_SOC_DAIFMT_DSP_B: 683 + ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; 684 + ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; 685 + invert_lrclk = false; 686 + break; 687 + default: 688 + return -EINVAL; 689 + } 690 + 691 + if (invert_lrclk) 692 + block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL; 693 + 694 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, 695 + ADAU1977_BLOCK_POWER_SAI_LR_POL | 696 + ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power); 697 + if (ret) 698 + return ret; 699 + 700 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, 701 + ADAU1977_SAI_CTRL0_FMT_MASK, 702 + ctrl0); 703 + if (ret) 704 + return ret; 705 + 706 + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, 707 + ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE, 708 + ctrl1); 709 + } 710 + 711 + static int adau1977_startup(struct snd_pcm_substream *substream, 712 + struct snd_soc_dai *dai) 713 + { 714 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); 715 + u64 formats = 0; 716 + 717 + if (adau1977->slot_width == 16) 718 + formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE; 719 + else if (adau1977->right_j || adau1977->slot_width == 24) 720 + formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | 721 + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE; 722 + 723 + snd_pcm_hw_constraint_list(substream->runtime, 0, 724 + SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints); 725 + 726 + if (adau1977->master) 727 + snd_pcm_hw_constraint_minmax(substream->runtime, 728 + SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs); 729 + 730 + if (formats != 0) 731 + snd_pcm_hw_constraint_mask64(substream->runtime, 732 + SNDRV_PCM_HW_PARAM_FORMAT, formats); 733 + 734 + return 0; 735 + } 736 + 737 + static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate) 738 + { 739 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); 740 + unsigned int val; 741 + 742 + if (tristate) 743 + val = ADAU1977_SAI_OVERTEMP_DRV_HIZ; 744 + else 745 + val = 0; 746 + 747 + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, 748 + ADAU1977_SAI_OVERTEMP_DRV_HIZ, val); 749 + } 750 + 751 + static const struct snd_soc_dai_ops adau1977_dai_ops = { 752 + .startup = adau1977_startup, 753 + .hw_params = adau1977_hw_params, 754 + .mute_stream = adau1977_mute, 755 + .set_fmt = adau1977_set_dai_fmt, 756 + .set_tdm_slot = adau1977_set_tdm_slot, 757 + .set_tristate = adau1977_set_tristate, 758 + }; 759 + 760 + static struct snd_soc_dai_driver adau1977_dai = { 761 + .name = "adau1977-hifi", 762 + .capture = { 763 + .stream_name = "Capture", 764 + .channels_min = 1, 765 + .channels_max = 4, 766 + .rates = SNDRV_PCM_RATE_KNOT, 767 + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 768 + SNDRV_PCM_FMTBIT_S32_LE, 769 + .sig_bits = 24, 770 + }, 771 + .ops = &adau1977_dai_ops, 772 + }; 773 + 774 + static const unsigned int adau1977_rates[] = { 775 + 8000, 16000, 32000, 64000, 128000, 776 + 11025, 22050, 44100, 88200, 172400, 777 + 12000, 24000, 48000, 96000, 192000, 778 + }; 779 + 780 + #define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f 781 + #define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0 782 + #define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00 783 + /* All rates >= 32000 */ 784 + #define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c 785 + 786 + static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq) 787 + { 788 + unsigned int mcs; 789 + 790 + if (mclk % (base_freq * 128) != 0) 791 + return false; 792 + 793 + mcs = mclk / (128 * base_freq); 794 + if (mcs < 1 || mcs > 6 || mcs == 5) 795 + return false; 796 + 797 + return true; 798 + } 799 + 800 + static int adau1977_set_sysclk(struct snd_soc_codec *codec, 801 + int clk_id, int source, unsigned int freq, int dir) 802 + { 803 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); 804 + unsigned int mask = 0; 805 + unsigned int clk_src; 806 + unsigned int ret; 807 + 808 + if (dir != SND_SOC_CLOCK_IN) 809 + return -EINVAL; 810 + 811 + if (clk_id != ADAU1977_SYSCLK) 812 + return -EINVAL; 813 + 814 + switch (source) { 815 + case ADAU1977_SYSCLK_SRC_MCLK: 816 + clk_src = 0; 817 + break; 818 + case ADAU1977_SYSCLK_SRC_LRCLK: 819 + clk_src = ADAU1977_PLL_CLK_S; 820 + break; 821 + default: 822 + return -EINVAL; 823 + } 824 + 825 + if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) { 826 + if (freq < 4000000 || freq > 36864000) 827 + return -EINVAL; 828 + 829 + if (adau1977_check_sysclk(freq, 32000)) 830 + mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000; 831 + if (adau1977_check_sysclk(freq, 44100)) 832 + mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100; 833 + if (adau1977_check_sysclk(freq, 48000)) 834 + mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000; 835 + 836 + if (mask == 0) 837 + return -EINVAL; 838 + } else if (source == ADAU1977_SYSCLK_SRC_LRCLK) { 839 + mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK; 840 + } 841 + 842 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, 843 + ADAU1977_PLL_CLK_S, clk_src); 844 + if (ret) 845 + return ret; 846 + 847 + adau1977->constraints.mask = mask; 848 + adau1977->sysclk_src = source; 849 + adau1977->sysclk = freq; 850 + 851 + return 0; 852 + } 853 + 854 + static int adau1977_codec_probe(struct snd_soc_codec *codec) 855 + { 856 + struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); 857 + int ret; 858 + 859 + switch (adau1977->type) { 860 + case ADAU1977: 861 + ret = snd_soc_dapm_new_controls(&codec->dapm, 862 + adau1977_micbias_dapm_widgets, 863 + ARRAY_SIZE(adau1977_micbias_dapm_widgets)); 864 + if (ret < 0) 865 + return ret; 866 + break; 867 + default: 868 + break; 869 + } 870 + 871 + return 0; 872 + } 873 + 874 + static struct snd_soc_codec_driver adau1977_codec_driver = { 875 + .probe = adau1977_codec_probe, 876 + .set_bias_level = adau1977_set_bias_level, 877 + .set_sysclk = adau1977_set_sysclk, 878 + .idle_bias_off = true, 879 + 880 + .controls = adau1977_snd_controls, 881 + .num_controls = ARRAY_SIZE(adau1977_snd_controls), 882 + .dapm_widgets = adau1977_dapm_widgets, 883 + .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets), 884 + .dapm_routes = adau1977_dapm_routes, 885 + .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), 886 + }; 887 + 888 + static int adau1977_setup_micbias(struct adau1977 *adau1977) 889 + { 890 + struct adau1977_platform_data *pdata = adau1977->dev->platform_data; 891 + unsigned int micbias; 892 + 893 + if (pdata) { 894 + micbias = pdata->micbias; 895 + if (micbias > ADAU1977_MICBIAS_9V0) 896 + return -EINVAL; 897 + 898 + } else { 899 + micbias = ADAU1977_MICBIAS_8V5; 900 + } 901 + 902 + return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS, 903 + ADAU1977_MICBIAS_MB_VOLTS_MASK, 904 + micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET); 905 + } 906 + 907 + int adau1977_probe(struct device *dev, struct regmap *regmap, 908 + enum adau1977_type type, void (*switch_mode)(struct device *dev)) 909 + { 910 + unsigned int power_off_mask; 911 + struct adau1977 *adau1977; 912 + int ret; 913 + 914 + if (IS_ERR(regmap)) 915 + return PTR_ERR(regmap); 916 + 917 + adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL); 918 + if (adau1977 == NULL) 919 + return -ENOMEM; 920 + 921 + adau1977->dev = dev; 922 + adau1977->type = type; 923 + adau1977->regmap = regmap; 924 + adau1977->switch_mode = switch_mode; 925 + adau1977->max_master_fs = 192000; 926 + 927 + adau1977->constraints.list = adau1977_rates; 928 + adau1977->constraints.count = ARRAY_SIZE(adau1977_rates); 929 + 930 + adau1977->avdd_reg = devm_regulator_get(dev, "AVDD"); 931 + if (IS_ERR(adau1977->avdd_reg)) 932 + return PTR_ERR(adau1977->avdd_reg); 933 + 934 + adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD"); 935 + if (IS_ERR(adau1977->dvdd_reg)) { 936 + if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV) 937 + return PTR_ERR(adau1977->dvdd_reg); 938 + adau1977->dvdd_reg = NULL; 939 + } 940 + 941 + adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); 942 + if (IS_ERR(adau1977->reset_gpio)) { 943 + ret = PTR_ERR(adau1977->reset_gpio); 944 + if (ret != -ENOENT && ret != -ENOSYS) 945 + return PTR_ERR(adau1977->reset_gpio); 946 + adau1977->reset_gpio = NULL; 947 + } 948 + 949 + dev_set_drvdata(dev, adau1977); 950 + 951 + if (adau1977->reset_gpio) { 952 + ret = gpiod_direction_output(adau1977->reset_gpio, 0); 953 + if (ret) 954 + return ret; 955 + ndelay(100); 956 + } 957 + 958 + ret = adau1977_power_enable(adau1977); 959 + if (ret) 960 + return ret; 961 + 962 + if (type == ADAU1977) { 963 + ret = adau1977_setup_micbias(adau1977); 964 + if (ret) 965 + goto err_poweroff; 966 + } 967 + 968 + if (adau1977->dvdd_reg) 969 + power_off_mask = ~0; 970 + else 971 + power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN; 972 + 973 + ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, 974 + power_off_mask, 0x00); 975 + if (ret) 976 + goto err_poweroff; 977 + 978 + ret = adau1977_power_disable(adau1977); 979 + if (ret) 980 + return ret; 981 + 982 + return snd_soc_register_codec(dev, &adau1977_codec_driver, 983 + &adau1977_dai, 1); 984 + 985 + err_poweroff: 986 + adau1977_power_disable(adau1977); 987 + return ret; 988 + 989 + } 990 + EXPORT_SYMBOL_GPL(adau1977_probe); 991 + 992 + static bool adau1977_register_volatile(struct device *dev, unsigned int reg) 993 + { 994 + switch (reg) { 995 + case ADAU1977_REG_STATUS(0): 996 + case ADAU1977_REG_STATUS(1): 997 + case ADAU1977_REG_STATUS(2): 998 + case ADAU1977_REG_STATUS(3): 999 + case ADAU1977_REG_ADC_CLIP: 1000 + return true; 1001 + } 1002 + 1003 + return false; 1004 + } 1005 + 1006 + const struct regmap_config adau1977_regmap_config = { 1007 + .max_register = ADAU1977_REG_DC_HPF_CAL, 1008 + .volatile_reg = adau1977_register_volatile, 1009 + 1010 + .cache_type = REGCACHE_RBTREE, 1011 + .reg_defaults = adau1977_reg_defaults, 1012 + .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults), 1013 + }; 1014 + EXPORT_SYMBOL_GPL(adau1977_regmap_config); 1015 + 1016 + MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); 1017 + MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 1018 + MODULE_LICENSE("GPL");
+37
sound/soc/codecs/adau1977.h
··· 1 + /* 2 + * ADAU1977/ADAU1978/ADAU1979 driver 3 + * 4 + * Copyright 2014 Analog Devices Inc. 5 + * Author: Lars-Peter Clausen <lars@metafoo.de> 6 + * 7 + * Licensed under the GPL-2. 8 + */ 9 + 10 + #ifndef __SOUND_SOC_CODECS_ADAU1977_H__ 11 + #define __SOUND_SOC_CODECS_ADAU1977_H__ 12 + 13 + #include <linux/regmap.h> 14 + 15 + struct device; 16 + 17 + enum adau1977_type { 18 + ADAU1977, 19 + ADAU1978, 20 + ADAU1979, 21 + }; 22 + 23 + int adau1977_probe(struct device *dev, struct regmap *regmap, 24 + enum adau1977_type type, void (*switch_mode)(struct device *dev)); 25 + 26 + extern const struct regmap_config adau1977_regmap_config; 27 + 28 + enum adau1977_clk_id { 29 + ADAU1977_SYSCLK, 30 + }; 31 + 32 + enum adau1977_sysclk_src { 33 + ADAU1977_SYSCLK_SRC_MCLK, 34 + ADAU1977_SYSCLK_SRC_LRCLK, 35 + }; 36 + 37 + #endif