diff options
author | Inha Song <ideal.song@samsung.com> | 2014-11-10 13:40:23 +0900 |
---|---|---|
committer | Seung-Woo Kim <sw0312.kim@samsung.com> | 2016-12-14 13:40:50 +0900 |
commit | adf20b9c4ff6093f4aa1a51cae5e3ef34728f2d6 (patch) | |
tree | 78a750a22597320de3554de74f872851507e2d09 /sound | |
parent | 33a8621763a7a9baa302d9632f22689f4117c9eb (diff) |
LOCAL / ASoC: max98504A: Add max98504A Speaker amplifier driver
This patch add MAX98504A Class D Speaker Amplifier driver.
The MAX98504A is a high efficiency mono Class D audio amplifier
that features an integrated boost converter with voltage and current
sensing ADCs for dynamic speaker management solutions.
Signed-off-by: Inha Song <ideal.song@samsung.com>
[k.kozlowski: rebased on 4.1]
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/max98504a.c | 655 | ||||
-rw-r--r-- | sound/soc/codecs/max98504a.h | 590 |
4 files changed, 1251 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..3b5b2b4434a4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -465,6 +465,10 @@ config SND_SOC_MAX98357A config SND_SOC_MAX98925 tristate +config SND_SOC_MAX98504A + tristate "Support MAX98504A Amplifier" + depends on I2C + config SND_SOC_MAX9850 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..667b461bdaf2 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -178,6 +178,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o # Amp snd-soc-max9877-objs := max9877.o +snd-soc-max98504a-objs := max98504a.o snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o @@ -360,4 +361,5 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o +obj-$(CONFIG_SND_SOC_MAX98504A) += snd-soc-max98504a.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o diff --git a/sound/soc/codecs/max98504a.c b/sound/soc/codecs/max98504a.c new file mode 100644 index 000000000000..6e963c12318c --- /dev/null +++ b/sound/soc/codecs/max98504a.c @@ -0,0 +1,655 @@ +/* +* max98504.c -- MAX98504 SoC Audio driver +* +* Copyright 2013-2014 Maxim Integrated Products +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +*/ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <sound/soc.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <sound/tlv.h> +#include <sound/tlv.h> +#include <sound/max98504a.h> +#include <linux/delay.h> +#include <linux/regulator/consumer.h> +#include <linux/of_gpio.h> + +#include "max98504a.h" +#ifdef CONFIG_SND_SOC_MAXIM_DSM_A +#include <sound/maxim_dsm_a.h> +#endif + +#ifdef DEBUG_MAX98504 +#define msg_maxim(format, args...) \ + printk(KERN_INFO "[MAX98504_DEBUG] %s " format, __func__, ## args) +#else +#define msg_maxim(format, args...) +#endif + +static struct regmap *regmap; + +static DEFINE_MUTEX(max98504_lock); + +static struct reg_default max98504_reg[] = { + {MAX98504_REG_01_INTERRUPT_STATUS, 0x00}, + {MAX98504_REG_02_INTERRUPT_FLAGS, 0x00}, + {MAX98504_REG_03_INTERRUPT_ENABLES, 0x00}, + {MAX98504_REG_04_INTERRUPT_FLAG_CLEARS, 0x00}, + {MAX98504_REG_10_GPIO_ENABLE, 0x00}, + {MAX98504_REG_11_GPIO_CONFIG, 0x00}, + {MAX98504_REG_12_WATCHDOG_ENABLE, 0x00}, + {MAX98504_REG_13_WATCHDOG_CONFIG, 0x00}, + {MAX98504_REG_14_WATCHDOG_CLEAR, 0x00}, + {MAX98504_REG_15_CLOCK_MONITOR_ENABLE, 0x00}, + {MAX98504_REG_16_PVDD_BROWNOUT_ENABLE, 0x00}, + {MAX98504_REG_17_PVDD_BROWNOUT_CONFIG_1, 0x00}, + {MAX98504_REG_18_PVDD_BROWNOUT_CONFIG_2, 0x00}, + {MAX98504_REG_19_PVDD_BROWNOUT_CONFIG_3, 0x00}, + {MAX98504_REG_1A_PVDD_BROWNOUT_CONFIG_4, 0x00}, + {MAX98504_REG_20_PCM_RX_ENABLES, 0x00}, + {MAX98504_REG_21_PCM_TX_ENABLES, 0x00}, + {MAX98504_REG_22_PCM_TX_HIZ_CONTROL, 0x00}, + {MAX98504_REG_23_PCM_TX_CHANNEL_SOURCES, 0x00}, + {MAX98504_REG_24_PCM_MODE_CONFIG, 0x00}, + {MAX98504_REG_25_PCM_DSP_CONFIG, 0x00}, + {MAX98504_REG_26_PCM_CLOCK_SETUP, 0x00}, + {MAX98504_REG_27_PCM_SAMPLE_RATE_SETUP, 0x00}, + {MAX98504_REG_28_PCM_TO_SPEAKER_MONOMIX, 0x00}, + {MAX98504_REG_30_PDM_TX_ENABLES, 0x00}, + {MAX98504_REG_31_PDM_TX_HIZ_CONTROL, 0x00}, + {MAX98504_REG_32_PDM_TX_CONTROL, 0x00}, + {MAX98504_REG_33_PDM_RX_ENABLE, 0x00}, + {MAX98504_REG_34_SPEAKER_ENABLE, 0x00}, + {MAX98504_REG_35_SPEAKER_SOURCE_SELECT, 0x00}, + {MAX98504_REG_36_MEASUREMENT_ENABLES, 0x00}, + {MAX98504_REG_37_ANALOGUE_INPUT_GAIN, 0x00}, + {MAX98504_REG_38_TEMPERATURE_LIMIT_CONFIG, 0x00}, + {MAX98504_REG_39_ANALOGUE_SPARE, 0x00}, + {MAX98504_REG_40_GLOBAL_ENABLE, 0x00}, + {MAX98504_REG_41_SOFTWARE_RESET, 0x00}, +}; + +static struct { + u8 read; + u8 write; + u8 vol; +} max98504_reg_access[MAX98504_REG_CNT] = { + [MAX98504_REG_01_INTERRUPT_STATUS] = { 0xFF, 0x00, 0xFF }, + [MAX98504_REG_02_INTERRUPT_FLAGS] = { 0xFF, 0x00, 0xFF }, + [MAX98504_REG_03_INTERRUPT_ENABLES] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_04_INTERRUPT_FLAG_CLEARS] = { 0x00, 0xFF, 0xFF }, + [MAX98504_REG_10_GPIO_ENABLE] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_11_GPIO_CONFIG] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_12_WATCHDOG_ENABLE] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_13_WATCHDOG_CONFIG] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_14_WATCHDOG_CLEAR] = { 0x00, 0xFF, 0xFF }, + [MAX98504_REG_15_CLOCK_MONITOR_ENABLE] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_16_PVDD_BROWNOUT_ENABLE] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_17_PVDD_BROWNOUT_CONFIG_1] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_18_PVDD_BROWNOUT_CONFIG_2] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_19_PVDD_BROWNOUT_CONFIG_3] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_1A_PVDD_BROWNOUT_CONFIG_4] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_20_PCM_RX_ENABLES] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_21_PCM_TX_ENABLES] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_22_PCM_TX_HIZ_CONTROL] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_23_PCM_TX_CHANNEL_SOURCES] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_24_PCM_MODE_CONFIG] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_25_PCM_DSP_CONFIG] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_26_PCM_CLOCK_SETUP] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_27_PCM_SAMPLE_RATE_SETUP] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_28_PCM_TO_SPEAKER_MONOMIX] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_30_PDM_TX_ENABLES] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_31_PDM_TX_HIZ_CONTROL] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_32_PDM_TX_CONTROL] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_33_PDM_RX_ENABLE] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_34_SPEAKER_ENABLE] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_35_SPEAKER_SOURCE_SELECT] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_36_MEASUREMENT_ENABLES] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_37_ANALOGUE_INPUT_GAIN] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_38_TEMPERATURE_LIMIT_CONFIG] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_39_ANALOGUE_SPARE] = { 0xFF, 0xFF, 0x00 }, + [MAX98504_REG_40_GLOBAL_ENABLE] = { 0xFF, 0xFF, 0xFF }, + [MAX98504_REG_41_SOFTWARE_RESET] = { 0x00, 0xFF, 0xFF }, +}; + +static bool max98504_volatile_register(struct device *dev, unsigned int reg) +{ + if (max98504_reg_access[reg].vol) + return 1; + else + return 0; +} + +static bool max98504_readable_register(struct device *dev, unsigned int reg) +{ + if (reg >= MAX98504_REG_CNT) + return 0; + return max98504_reg_access[reg].read != 0; +} + +static int max98504_reset(struct max98504_priv *max98504) +{ + int ret; + + ret = regmap_write(max98504->regmap, + MAX98504_REG_41_SOFTWARE_RESET, M98504_SOFTWARE_RESET_MASK); + msleep(20); + + return ret; +} + +#ifdef CONFIG_SND_SOC_MAXIM_DSM_A +#define DEFAULT_LOG_CLASS_NAME "dsm" +static ssize_t max98504_log_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return maxdsm_log_prepare(buf); +} + +static DEVICE_ATTR(dsm_log, S_IRUGO, max98504_log_show, NULL); +static struct attribute *max98504_attributes[] = { + &dev_attr_dsm_log.attr, + NULL +}; + +static struct attribute_group max98504_attribute_group = { + .attrs = max98504_attributes +}; +#endif + +static int max98504_probe(struct max98504_priv *max98504) +{ + struct max98504_pdata *pdata = max98504->pdata; + struct max98504_cfg_data *cfg_data = &pdata->cfg_data; + + u8 regval; + int ret; + unsigned int value; + + msg_maxim("\n"); + + max98504_reset(max98504); + + if (!pdata) { + pr_err("No platform data\n"); + return ret; + } + /* Configure Rx Mode */ + if (pdata->rx_mode == MODE_RX_PCM) { + regval = 0; + if (cfg_data->rx_dither_en) + regval |= M98504_PCM_DSP_CFG_RX_DITH_EN_MASK; + if (cfg_data->rx_flt_mode) + regval |= M98504_PCM_DSP_CFG_RX_FLT_MODE_MASK; + + regmap_update_bits(max98504->regmap, + MAX98504_REG_25_PCM_DSP_CONFIG, + M98504_PCM_DSP_CFG_RX_DITH_EN_MASK|\ + M98504_PCM_DSP_CFG_RX_FLT_MODE_MASK, + regval); + regmap_write(max98504->regmap, + MAX98504_REG_20_PCM_RX_ENABLES, (u8)cfg_data->rx_ch_en); + } else if (pdata->rx_mode == MODE_RX_PDM0 || \ + pdata->rx_mode == MODE_RX_PDM1) { + regmap_write(max98504->regmap, + MAX98504_REG_33_PDM_RX_ENABLE, M98504_PDM_RX_EN_MASK); + } else { + regmap_write(max98504->regmap, + MAX98504_REG_20_PCM_RX_ENABLES, 0); + regmap_write(max98504->regmap, + MAX98504_REG_33_PDM_RX_ENABLE, 0); + } + + regmap_write(max98504->regmap, + MAX98504_REG_35_SPEAKER_SOURCE_SELECT, + (u8) (M98504_SPK_SRC_SEL_MASK & pdata->rx_mode)); + + /* Configure Tx Mode */ + if (pdata->tx_mode == MODE_TX_PCM) { + regval = 0; + if (cfg_data->tx_dither_en) + regval |= M98504_PCM_DSP_CFG_TX_DITH_EN_MASK; + if (cfg_data->meas_dc_block_en) + regval |= M98504_PCM_DSP_CFG_MEAS_DCBLK_EN_MASK; + regmap_update_bits(max98504->regmap, + MAX98504_REG_25_PCM_DSP_CONFIG, + M98504_PCM_DSP_CFG_TX_DITH_EN_MASK|\ + M98504_PCM_DSP_CFG_MEAS_DCBLK_EN_MASK, regval); + + regmap_write(max98504->regmap, + MAX98504_REG_21_PCM_TX_ENABLES, (u8)cfg_data->tx_ch_en); + regmap_write(max98504->regmap, + MAX98504_REG_22_PCM_TX_HIZ_CONTROL, + (u8)cfg_data->tx_hiz_ch_en); + regmap_write(max98504->regmap, + MAX98504_REG_23_PCM_TX_CHANNEL_SOURCES, + (u8)cfg_data->tx_ch_src); + } else { + regmap_write(max98504->regmap, + MAX98504_REG_30_PDM_TX_ENABLES, (u8)cfg_data->tx_ch_en); + regmap_write(max98504->regmap, + MAX98504_REG_31_PDM_TX_HIZ_CONTROL, + (u8)cfg_data->tx_hiz_ch_en); + regmap_write(max98504->regmap, + MAX98504_REG_32_PDM_TX_CONTROL, + (u8)cfg_data->tx_ch_src); + } + + regmap_write(max98504->regmap, + MAX98504_REG_36_MEASUREMENT_ENABLES, + M98504_MEAS_I_EN_MASK | M98504_MEAS_V_EN_MASK); + + /* Brownout Protection */ + regmap_write(max98504->regmap, + MAX98504_REG_16_PVDD_BROWNOUT_ENABLE, 0x1); + regmap_write(max98504->regmap, + MAX98504_REG_17_PVDD_BROWNOUT_CONFIG_1, 0x33); + regmap_write(max98504->regmap, + MAX98504_REG_18_PVDD_BROWNOUT_CONFIG_2, 0x0a); + regmap_write(max98504->regmap, + MAX98504_REG_19_PVDD_BROWNOUT_CONFIG_3, 0xff); + regmap_write(max98504->regmap, + MAX98504_REG_1A_PVDD_BROWNOUT_CONFIG_4, 0xff); + + #ifdef USE_MAX98504_IRQ + if (gpio_is_valid(pdata->irq)) { + regmap_write(max98504->regmap, + MAX98504_REG_03_INTERRUPT_ENABLES, 0xff); + regmap_write(max98504->regmap, + MAX98504_REG_10_GPIO_ENABLE, 0x01); + } + #endif + + return ret; + +err_access: + return ret; +} + +int max98504_set_speaker_status(int OnOff) +{ + mutex_lock(&max98504_lock); + + if (regmap == NULL) { + pr_err("Speaker control is not available.\n"); + mutex_unlock(&max98504_lock); + return 0; + } + + pr_debug("%s: onoff=%d\n", __func__, OnOff); + if (OnOff) { + regmap_update_bits(regmap, MAX98504_REG_34_SPEAKER_ENABLE, + M98504_SPK_EN_MASK, M98504_SPK_EN_MASK); + regmap_update_bits(regmap, MAX98504_REG_40_GLOBAL_ENABLE, + M98504_GLOBAL_EN_MASK, M98504_GLOBAL_EN_MASK); + } else { + regmap_update_bits(regmap, MAX98504_REG_40_GLOBAL_ENABLE, + M98504_GLOBAL_EN_MASK, 0); + regmap_update_bits(regmap, MAX98504_REG_34_SPEAKER_ENABLE, + M98504_SPK_EN_MASK, 0); + } + + mutex_unlock(&max98504_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(max98504_set_speaker_status); + +bool max98504_get_speaker_status(void) +{ + unsigned int ret; + mutex_lock(&max98504_lock); + + if (regmap == NULL) { + pr_err("Speaker control is not allowed.\n"); + return 0; + } + regmap_read(regmap, MAX98504_REG_34_SPEAKER_ENABLE, &ret); + + mutex_unlock(&max98504_lock); + return (ret > 0) ? true : false; +} +EXPORT_SYMBOL_GPL(max98504_get_speaker_status); + +static const struct regmap_config max98504_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MAX98504_REG_CNT, + .reg_defaults = max98504_reg, + .num_reg_defaults = ARRAY_SIZE(max98504_reg), + .volatile_reg = max98504_volatile_register, + .readable_reg = max98504_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA) +{ + return (regulator_count_voltages(reg) > 0) ? + regulator_set_load(reg, load_uA) : 0; +} + +static int max98504_regulator_config(struct i2c_client *i2c, + bool pullup, bool on) +{ + struct regulator *max98504_vcc_i2c; + int rc; + #define VCC_I2C_MIN_UV 1800000 + #define VCC_I2C_MAX_UV 1800000 + #define I2C_LOAD_UA 300000 + + msg_maxim("pullup=%d\n", pullup); + + if (pullup) { + max98504_vcc_i2c = regulator_get(&i2c->dev, "vcc_i2c"); + + if (IS_ERR(max98504_vcc_i2c)) { + rc = PTR_ERR(max98504_vcc_i2c); + pr_err("Regulator get failed rc=%d\n", rc); + return rc; + } + + if (regulator_count_voltages(max98504_vcc_i2c) > 0) { + rc = regulator_set_voltage(max98504_vcc_i2c, + VCC_I2C_MIN_UV, VCC_I2C_MAX_UV); + if (rc) { + pr_err("regulator set_vtg failed rc=%d\n", rc); + goto error_set_vtg_i2c; + } + } + + rc = reg_set_optimum_mode_check(max98504_vcc_i2c, I2C_LOAD_UA); + if (rc < 0) { + pr_err("Regulator vcc_i2c set_opt failed rc=%d\n", rc); + goto error_reg_opt_i2c; + } + + rc = regulator_enable(max98504_vcc_i2c); + if (rc) { + pr_err("Regulator vcc_i2c enable failed rc=%d\n", rc); + goto error_reg_en_vcc_i2c; + } + } + + return 0; + +error_reg_en_vcc_i2c: + if (pullup) + reg_set_optimum_mode_check(max98504_vcc_i2c, 0); +error_reg_opt_i2c: + regulator_disable(max98504_vcc_i2c); +error_set_vtg_i2c: + regulator_put(max98504_vcc_i2c); + + return rc; +} + +#ifdef USE_MAX98504_IRQ +static irqreturn_t max98504_interrupt(int irq, void *data) +{ + struct max98504_priv *max98504 = (struct max98504_priv *) data; + + unsigned int mask; + unsigned int flag; + + regmap_read(max98504->regmap, MAX98504_REG_03_INTERRUPT_ENABLES, &mask); + regmap_read(max98504->regmap, MAX98504_REG_02_INTERRUPT_FLAGS, &flag); + + pr_debug("max98504_irq! flag=0x%02x mask=0x%02x -> flag=0x%02x\n", + flag, mask, flag & mask); + + flag &= mask; + + if (!flag) + return IRQ_NONE; + + /* Send work to be scheduled */ + if (flag & M98504_INT_GENFAIL_EN_MASK) + msg_maxim("M98504_INT_GENFAIL_EN_MASK active!"); + + if (flag & M98504_INT_AUTHDONE_EN_MASK) + msg_maxim("M98504_INT_AUTHDONE_EN_MASK active!"); + + if (flag & M98504_INT_VBATBROWN_EN_MASK) + msg_maxim("M98504_INT_VBATBROWN_EN_MASK active!"); + + if (flag & M98504_INT_WATCHFAIL_EN_MASK) + msg_maxim("M98504_INT_WATCHFAIL_EN_MASK active!"); + + if (flag & M98504_INT_THERMWARN_END_EN_MASK) + msg_maxim("M98504_INT_THERMWARN_END_EN_MASK active!"); + + if (flag & M98504_INT_THERMWARN_BGN_EN_MASK) + msg_maxim("M98504_INT_THERMWARN_BGN_EN_MASK active!\n"); + + if (flag & M98504_INT_THERMSHDN_END_EN_MASK) + msg_maxim("M98504_INT_THERMSHDN_END_EN_MASK active!\n"); + + if (flag & M98504_INT_THERMSHDN_BGN_FLAG_MASK) + msg_maxim("M98504_INT_THERMSHDN_BGN_FLAG_MASK active!\n"); + + regmap_write(max98504->regmap, + MAX98504_REG_04_INTERRUPT_FLAG_CLEARS, flag&0xff); + + return IRQ_HANDLED; +} +#endif + +static int max98504_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max98504_priv *max98504; + struct max98504_pdata *pdata; + int ret = 0; +#ifdef CONFIG_SND_SOC_MAXIM_DSM_A + const char *of_class_name = DEFAULT_LOG_CLASS_NAME; + const char *class_name_log; +#endif + + msg_maxim("\n"); + + max98504 = kzalloc(sizeof(struct max98504_priv), GFP_KERNEL); + if (max98504 == NULL) + return -ENOMEM; + + max98504->devtype = id->driver_data; + i2c_set_clientdata(i2c, max98504); + max98504->control_data = i2c; + + if (i2c->dev.of_node) { + max98504->pdata = devm_kzalloc(&i2c->dev, + sizeof(struct max98504_pdata), GFP_KERNEL); + if (!max98504->pdata) { + dev_err(&i2c->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } else + pdata = max98504->pdata; + + #ifdef USE_MAX98504_IRQ + pdata->irq = of_get_named_gpio_flags(i2c->dev.of_node, + "max98504,irq-gpio", 0, NULL); + #endif + + ret = of_property_read_u32(i2c->dev.of_node, + "max98504,rx_mode", &pdata->rx_mode); + if (ret) { + dev_err(&i2c->dev, "Failed to read rx_mode.\n"); + return -EINVAL; + } + + ret = of_property_read_u32(i2c->dev.of_node, + "max98504,tx_mode", &pdata->tx_mode); + if (ret) { + dev_err(&i2c->dev, "Failed to read tx_mode.\n"); + return -EINVAL; + } + + ret = of_property_read_u32_array(i2c->dev.of_node, + "max98504,cfg_data", (u32 *) &pdata->cfg_data, + sizeof(struct max98504_cfg_data)/sizeof(u32)); + if (ret) { + dev_err(&i2c->dev, "Failed to read cfg_data.\n"); + return -EINVAL; + } + #ifdef CONFIG_SND_SOC_MAXIM_DSM_A + ret = of_property_read_string(i2c->dev.of_node, + "max98504,log_class", &of_class_name); + if (ret) { + dev_err(&i2c->dev, "Failed to read log_class.\n"); + of_class_name = DEFAULT_LOG_CLASS_NAME; + } + #endif + msg_maxim("rx_mode:%d, tx_mode:%d, tx_dither_en:%d"\ + ", rx_dither_en:%d, meas_dc_block_en:%d"\ + ", rx_flt_mode:%d, rx_ch_en:%d\n", + pdata->rx_mode, + pdata->tx_mode, + pdata->cfg_data.tx_dither_en, + pdata->cfg_data.rx_dither_en, + pdata->cfg_data.meas_dc_block_en, + pdata->cfg_data.rx_flt_mode, + pdata->cfg_data.rx_ch_en); + msg_maxim("tx_ch_en:%d, tx_hiz_ch_en:%d"\ + ", tx_ch_src:%d, auth_en:%d, wdog_time_out:%d\n", + pdata->cfg_data.tx_ch_en, + pdata->cfg_data.tx_hiz_ch_en, + pdata->cfg_data.tx_ch_src, + pdata->cfg_data.auth_en, + pdata->cfg_data.wdog_time_out); + } else { + max98504->pdata = i2c->dev.platform_data; + pdata = max98504->pdata; + } + + max98504_regulator_config(i2c, + of_property_read_bool(i2c->dev.of_node, + "max98504,i2c-pull-up"), 1); + + max98504->regmap = regmap = regmap_init_i2c(i2c, &max98504_regmap); + + if (IS_ERR(max98504->regmap)) { + ret = PTR_ERR(max98504->regmap); + dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); + goto err_out; + } + + max98504_probe(max98504); + +#ifdef CONFIG_SND_SOC_MAXIM_DSM_A + class_name_log = of_class_name; + + max98504->dev_log_class = + class_create(THIS_MODULE, class_name_log); + if (max98504->dev_log_class == NULL) { + pr_err("%s: class_create fail.\n", __func__); + } else { + max98504->dev_log = device_create(max98504->dev_log_class, NULL, + 1, NULL, "max98504"); + if (IS_ERR(max98504->dev_log)) { + ret = sysfs_create_group(&i2c->dev.kobj, + &max98504_attribute_group); + if (ret) + msg_maxim(\ + "failed to create sysfs group [%d]", ret); + } else { + ret = sysfs_create_group(&max98504->dev_log->kobj, + &max98504_attribute_group); + if (ret) + msg_maxim("failed to create sysfs group [%d]", + ret); + } + } +#endif + +#ifdef USE_MAX98504_IRQ + if (pdata != NULL && gpio_is_valid(pdata->irq)) { + ret = gpio_request(pdata->irq, "max98504_irq_gpio"); + if (ret) { + dev_err(&i2c->dev, "unable to request gpio [%d]\n", + pdata->irq); + goto err_irq_gpio_req; + } + ret = gpio_direction_input(pdata->irq); + if (ret) { + dev_err(&i2c->dev, + "unable to set direction for gpio [%d]\n", + pdata->irq); + goto err_irq_gpio_req; + } + i2c->irq = gpio_to_irq(pdata->irq); + + ret = request_threaded_irq(i2c->irq, NULL, max98504_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "max98504_interrupt", max98504); + if (ret) + dev_err(&i2c->dev, "Failed to register interrupt\n"); + + } else { + dev_err(&i2c->dev, "irq gpio not provided\n"); + } + return 0; + +err_irq_gpio_req: + if (gpio_is_valid(pdata->irq)) + gpio_free(pdata->irq); + return 0; +#endif + +err_out: + if (ret < 0) { + if (max98504->regmap) + regmap_exit(max98504->regmap); + kfree(max98504); + } + + return 0; +} + +static int max98504_i2c_remove(struct i2c_client *client) +{ + struct max98504_priv *max98504 = dev_get_drvdata(&client->dev); + + if (max98504->regmap) + regmap_exit(max98504->regmap); + kfree(i2c_get_clientdata(client)); + + return 0; +} + +static const struct i2c_device_id max98504_i2c_id[] = { + { "max98504", MAX98504 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, max98504_i2c_id); + +static struct i2c_driver max98504_i2c_driver = { + .driver = { + .name = "max98504", + .owner = THIS_MODULE, + }, + .probe = max98504_i2c_probe, + .remove = max98504_i2c_remove, + .id_table = max98504_i2c_id, +}; + +static int __init max98504_init(void) +{ + return i2c_add_driver(&max98504_i2c_driver); +} +module_init(max98504_init); + +static void __exit max98504_exit(void) +{ + i2c_del_driver(&max98504_i2c_driver); +} +module_exit(max98504_exit); + +MODULE_DESCRIPTION("SoC MAX98504 driver"); +MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98504a.h b/sound/soc/codecs/max98504a.h new file mode 100644 index 000000000000..e45a930a2f9c --- /dev/null +++ b/sound/soc/codecs/max98504a.h @@ -0,0 +1,590 @@ +/* + * max98504.h -- MAX98504 ALSA SoC Audio driver + * + * Copyright 2011-2012 Maxim Integrated Products + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _MAX98504_H +#define _MAX98504_H + +#include <linux/version.h> + +int max98504_set_speaker_status(int OnOff); + +/* + * MAX98504 Register Definitions + */ +#define MAX98504_REG_01_INTERRUPT_STATUS 0x01 +#define MAX98504_REG_02_INTERRUPT_FLAGS 0x02 +#define MAX98504_REG_03_INTERRUPT_ENABLES 0x03 +#define MAX98504_REG_04_INTERRUPT_FLAG_CLEARS 0x04 +#define MAX98504_REG_10_GPIO_ENABLE 0x10 +#define MAX98504_REG_11_GPIO_CONFIG 0x11 +#define MAX98504_REG_12_WATCHDOG_ENABLE 0x12 +#define MAX98504_REG_13_WATCHDOG_CONFIG 0x13 +#define MAX98504_REG_14_WATCHDOG_CLEAR 0x14 +#define MAX98504_REG_15_CLOCK_MONITOR_ENABLE 0x15 +#define MAX98504_REG_16_PVDD_BROWNOUT_ENABLE 0x16 +#define MAX98504_REG_17_PVDD_BROWNOUT_CONFIG_1 0x17 +#define MAX98504_REG_18_PVDD_BROWNOUT_CONFIG_2 0x18 +#define MAX98504_REG_19_PVDD_BROWNOUT_CONFIG_3 0x19 +#define MAX98504_REG_1A_PVDD_BROWNOUT_CONFIG_4 0x1a +#define MAX98504_REG_20_PCM_RX_ENABLES 0x20 +#define MAX98504_REG_21_PCM_TX_ENABLES 0x21 +#define MAX98504_REG_22_PCM_TX_HIZ_CONTROL 0x22 +#define MAX98504_REG_23_PCM_TX_CHANNEL_SOURCES 0x23 +#define MAX98504_REG_24_PCM_MODE_CONFIG 0x24 +#define MAX98504_REG_25_PCM_DSP_CONFIG 0x25 +#define MAX98504_REG_26_PCM_CLOCK_SETUP 0x26 +#define MAX98504_REG_27_PCM_SAMPLE_RATE_SETUP 0x27 +#define MAX98504_REG_28_PCM_TO_SPEAKER_MONOMIX 0x28 +#define MAX98504_REG_30_PDM_TX_ENABLES 0x30 +#define MAX98504_REG_31_PDM_TX_HIZ_CONTROL 0x31 +#define MAX98504_REG_32_PDM_TX_CONTROL 0x32 +#define MAX98504_REG_33_PDM_RX_ENABLE 0x33 +#define MAX98504_REG_34_SPEAKER_ENABLE 0x34 +#define MAX98504_REG_35_SPEAKER_SOURCE_SELECT 0x35 +#define MAX98504_REG_36_MEASUREMENT_ENABLES 0x36 +#define MAX98504_REG_37_ANALOGUE_INPUT_GAIN 0x37 +#define MAX98504_REG_38_TEMPERATURE_LIMIT_CONFIG 0x38 +#define MAX98504_REG_39_ANALOGUE_SPARE 0x39 +#define MAX98504_REG_40_GLOBAL_ENABLE 0x40 +#define MAX98504_REG_41_SOFTWARE_RESET 0x41 +#define MAX98504_REG_7FFF_REV_ID 0x7fff + +#define MAX98504_REG_CNT (MAX98504_REG_41_SOFTWARE_RESET+1) + +/* MAX98504 Register Bit Fields */ + +/* MAX98504_REG_01_INTERRUPT_STATUS*/ +#define M98504_INT_GENFAIL_STATUS_MASK (1<<7) +#define M98504_INT_GENFAIL_STATUS_SHIFT 7 +#define M98504_INT_GENFAIL_STATUS_WIDTH 1 + +#define M98504_INT_AUTHDONE_STATUS_MASK (1<<6) +#define M98504_INT_AUTHDONE_STATUS_SHIFT 6 +#define M98504_INT_AUTHDONE_STATUS_WIDTH 1 + +#define M98504_INT_VBATBROWN_STATUS_MASK (1<<5) +#define M98504_INT_VBATBROWN_STATUS_SHIFT 5 +#define M98504_INT_VBATBROWN_STATUS_WIDTH 1 + +#define M98504_INT_WATCHFAIL_STATUS_MASK (1<<4) +#define M98504_INT_WATCHFAIL_STATUS_SHIFT 4 +#define M98504_INT_WATCHFAIL_STATUS_WIDTH 1 + +#define M98504_INT_THERMWARN_STATUS_MASK (1<<3) +#define M98504_INT_THERMWARN_STATUS_SHIFT 3 +#define M98504_INT_THERMWARN_STATUS_WIDTH 1 + +#define M98504_INT_THERMSHDN_STATUS_MASK (1<<1) +#define M98504_INT_THERMSHDN_STATUS_SHIFT 1 +#define M98504_INT_THERMSHDN_STATUS_WIDTH 1 + +#define M98504_INT_INTERRUPT_STATUS_MASK (\ + M98504_INT_GENFAIL_STATUS_MASK|M98504_INT_AUTHDONE_STATUS_MASK\ + |M98504_INT_VBATBROWN_STATUS_MASK|M98504_INT_WATCHFAIL_STATUS_MASK\ + |M98504_INT_THERMWARN_STATUS_MASK|M98504_INT_THERMSHDN_STATUS_MASK) + +/* MAX98504_REG_02_INTERRUPT_FLAGS*/ +#define M98504_INT_GENFAIL_FLAG_MASK (1<<7) +#define M98504_INT_GENFAIL_FLAG_SHIFT 7 +#define M98504_INT_GENFAIL_FLAG_WIDTH 1 + +#define M98504_INT_AUTHDONE_FLAG_MASK (1<<6) +#define M98504_INT_AUTHDONE_FLAG_SHIFT 6 +#define M98504_INT_AUTHDONE_FLAG_WIDTH 1 + +#define M98504_INT_VBATBROWN_FLAG_MASK (1<<5) +#define M98504_INT_VBATBROWN_FLAG_SHIFT 5 +#define M98504_INT_VBATBROWN_FLAG_WIDTH 1 + +#define M98504_INT_WATCHFAIL_FLAG_MASK (1<<4) +#define M98504_INT_WATCHFAIL_FLAG_SHIFT 4 +#define M98504_INT_WATCHFAIL_FLAG_WIDTH 1 + +#define M98504_INT_THERMWARN_END_FLAG_MASK (1<<3) +#define M98504_INT_THERMWARN_END_FLAG_SHIFT 3 +#define M98504_INT_THERMWARN_END_FLAG_WIDTH 1 + +#define M98504_INT_THERMWARN_BGN_FLAG_MASK (1<<2) +#define M98504_INT_THERMWARN_BGN_FLAG_SHIFT 2 +#define M98504_INT_THERMWARN_BGN_FLAG_WIDTH 1 + +#define M98504_INT_THERMSHDN_END_EN_MASK (1<<1) +#define M98504_INT_THERMSHDN_END_FLAG_SHIFT 1 +#define M98504_INT_THERMSHDN_END_FLAG_WIDTH 1 + +#define M98504_INT_THERMSHDN_BGN_FLAG_MASK (1<<0) +#define M98504_INT_THERMSHDN_BGN_FLAG_SHIFT 0 +#define M98504_INT_THERMSHDN_BGN_FLAG_WIDTH 1 + +/* MAX98504_REG_03_INTERRUPT_ENABLES*/ +#define M98504_INT_GENFAIL_EN_MASK (1<<7) +#define M98504_INT_GENFAIL_EN_SHIFT 7 +#define M98504_INT_GENFAIL_EN_WIDTH 1 + +#define M98504_INT_AUTHDONE_EN_MASK (1<<6) +#define M98504_INT_AUTHDONE_EN_SHIFT 6 +#define M98504_INT_AUTHDONE_EN_WIDTH 1 + +#define M98504_INT_VBATBROWN_EN_MASK (1<<5) +#define M98504_INT_VBATBROWN_EN_SHIFT 5 +#define M98504_INT_VBATBROWN_EN_WIDTH 1 + +#define M98504_INT_WATCHFAIL_EN_MASK (1<<4) +#define M98504_INT_WATCHFAIL_EN_SHIFT 4 +#define M98504_INT_WATCHFAIL_EN_WIDTH 1 + +#define M98504_INT_THERMWARN_END_EN_MASK (1<<3) +#define M98504_INT_THERMWARN_END_EN_SHIFT 3 +#define M98504_INT_THERMWARN_END_EN_WIDTH 1 + +#define M98504_INT_THERMWARN_BGN_EN_MASK (1<<2) +#define M98504_INT_THERMWARN_BGN_EN_SHIFT 2 +#define M98504_INT_THERMWARN_BGN_EN_WIDTH 1 + +#define M98504_INT_THERMSHDN_END_EN_MASK (1<<1) +#define M98504_INT_THERMSHDN_END_EN_SHIFT 1 +#define M98504_INT_THERMSHDN_END_EN_WIDTH 1 + +#define M98504_INT_THERMSHDN_BGN_EN_MASK (1<<0) +#define M98504_INT_THERMSHDN_BGN_EN_SHIFT 0 +#define M98504_INT_THERMSHDN_BGN_EN_WIDTH 1 + +/* MAX98504_REG_04_INTERRUPT_FLAG_CLEARS*/ +#define M98504_INT_FLAG_GENFAIL_CLR_MASK (1<<7) +#define M98504_INT_FLAG_GENFAIL_CLR_SHIFT 7 +#define M98504_INT_FLAG_GENFAIL_CLR_WIDTH 1 + +#define M98504_INT_FLAG_AUTHDONE_CLR_MASK (1<<6) +#define M98504_INT_FLAG_AUTHDONE_CLR_SHIFT 6 +#define M98504_INT_FLAG_AUTHDONE_CLR_WIDTH 1 + +#define M98504_INT_FLAG_VBATBROWN_CLR_MASK (1<<5) +#define M98504_INT_FLAG_VBATBROWN_CLR_SHIFT 5 +#define M98504_INT_FLAG_VBATBROWN_CLR_WIDTH 1 + +#define M98504_INT_FLAG_WATCHFAIL_CLR_MASK (1<<4) +#define M98504_INT_FLAG_WATCHFAIL_CLR_SHIFT 4 +#define M98504_INT_FLAG_WATCHFAIL_CLR_WIDTH 1 + +#define M98504_INT_FLAG_THERMWARN_END_CLR_MASK (1<<3) +#define M98504_INT_FLAG_THERMWARN_END_CLR_SHIFT 3 +#define M98504_INT_FLAG_THERMWARN_END_CLR_WIDTH 1 + +#define M98504_INT_FLAG_THERMWARN_BGN_CLR_MASK (1<<2) +#define M98504_INT_FLAG_THERMWARN_BGN_CLR_SHIFT 2 +#define M98504_INT_FLAG_THERMWARN_BGN_CLR_WIDTH 1 + +#define M98504_INT_FLAG_THERMSHDN_END_CLR_MASK (1<<1) +#define M98504_INT_FLAG_THERMSHDN_END_CLR_SHIFT 1 +#define M98504_INT_FLAG_THERMSHDN_END_CLR_WIDTH 1 + +#define M98504_INT_FLAG_THERMSHDN_BGN_CLR_MASK (1<<0) +#define M98504_INT_FLAG_THERMSHDN_BGN_CLR_SHIFT 0 +#define M98504_INT_FLAG_THERMSHDN_BGN_CLR_WIDTH 1 + +/* MAX98504_REG_10_GPIO_ENABLE*/ +#define M98504_GPIO_ENABLE_MASK (1<<0) +#define M98504_GPIO_ENALBE_SHIFT 0 +#define M98504_GPIO_ENABLE_WIDTH 1 + +/* MAX98504_REG_11_GPIO_CONFIG*/ +#define M98504_GPIO_OP_MODE_MASK (1<<0) +#define M98504_GPIO_OP_MODE_SHIFT 0 +#define M98504_GPIO_OP_MODE_WIDTH 1 + +/* MAX98504_REG_12_WATCHDOG_ENABLE*/ +#define M98504_WDOG_ENABLE_MASK (1<<0) +#define M98504_WDOG_ENABLE_SHIFT 0 +#define M98504_WDOG_ENABLE_WIDTH 1 + +/* MAX98504_REG_13_WATCHDOG_CONFIG*/ +#define M98504_WDOG_CONFIG_MASK (0x3<<0) +#define M98504_WDOG_CONFIG_SHIFT 0 +#define M98504_WDOG_CONFIG_WIDTH 2 + +#define M98504_WDOG_CONFIG_100MS 0 +#define M98504_WDOG_CONFIG_500MS 1 +#define M98504_WDOG_CONFIG_1000MS 2 +#define M98504_WDOG_CONFIG_2000MS 3 + +/* MAX98504_REG_14_WATCHDOG_CLEAR*/ +#define M98504_WDOG_CLEAR_MASK (0xff<<0) +#define M98504_WDOG_CLEAR_SHIFT 0 +#define M98504_WDOG_CLEAR_WIDTH 8 + +/* MAX98504_REG_15_CLOCK_MONITOR_ENABLE*/ +#define M98504_CMON_ENA_MASK (1<<0) +#define M98504_CMON_ENA_SHIFT 0 +#define M98504_CMON_ENA_WIDTH 1 + +/* MAX98504_REG_16_PVDD_BROWNOUT_ENABLE*/ +#define M98504_PVDD_BROWNOUT_ENA_MASK (1<<0) +#define M98504_PVDD_BROWNOUT_ENA_SHIFT 0 +#define M98504_PVDD_BROWNOUT_ENA_WIDTH 1 + +/* MAX98504_REG_17_PVDD_BROWNOUT_CONFIG_1*/ +#define M98504_PVDD_BROWNOUT_CFG1_CODE_MASK (0x1f<<3) +#define M98504_PVDD_BROWNOUT_CFG1_CODE_SHIFT 3 +#define M98504_PVDD_BROWNOUT_CFG1_CODE_WIDTH 5 + +#define M98504_PVDD_BROWNOUT_CFG1_MAX_ATTEN_MASK (0x7<<0) +#define M98504_PVDD_BROWNOUT_CFG1_MAX_ATTEN_SHIFT 0 +#define M98504_PVDD_BROWNOUT_CFG1_MAX_ATTEN_WIDTH 3 + +/* MAX98504_REG_18_PVDD_BROWNOUT_CONFIG_2*/ +#define M98504_PVDD_BROWNOUT_CFG2_ATTK_HOLD_MASK (0xff<<0) +#define M98504_PVDD_BROWNOUT_CFG2_ATTK_HOLD_SHIFT 0 +#define M98504_PVDD_BROWNOUT_CFG2_ATTK_HOLD_WIDTH 8 + +/* MAX98504_REG_19_PVDD_BROWNOUT_CONFIG_3*/ +#define M98504_PVDD_BROWNOUT_CFG3_TIMED_HOLD_MASK (0xff<<0) +#define M98504_PVDD_BROWNOUT_CFG3_TIMED_HOLD_SHIFT 0 +#define M98504_PVDD_BROWNOUT_CFG3_TIMED_HOLD_WIDTH 8 + +/* MAX98504_REG_1A_PVDD_BROWNOUT_CONFIG_4*/ +#define M98504_PVDD_BROWNOUT_CFG4_RELEASE_MASK (0xff<<0) +#define M98504_PVDD_BROWNOUT_CFG4_RELEASE_SHIFT 0 +#define M98504_PVDD_BROWNOUT_CFG4_RELEASE_WIDTH 8 + +/* MAX98504_REG_20_PCM_RX_ENABLES*/ +#define M98504_PCM_RX_EN_CH7_MASK (1<<7) +#define M98504_PCM_RX_EN_CH7_SHIFT 7 +#define M98504_PCM_RX_EN_CH7_WIDTH 1 + +#define M98504_PCM_RX_EN_CH6_MASK (1<<6) +#define M98504_PCM_RX_EN_CH6_SHIFT 6 +#define M98504_PCM_RX_EN_CH6_WIDTH 1 + +#define M98504_PCM_RX_EN_CH5_MASK (1<<5) +#define M98504_PCM_RX_EN_CH5_SHIFT 5 +#define M98504_PCM_RX_EN_CH5_WIDTH 1 + +#define M98504_PCM_RX_EN_CH4_MASK (1<<4) +#define M98504_PCM_RX_EN_CH4_SHIFT 4 +#define M98504_PCM_RX_EN_CH4_WIDTH 1 + +#define M98504_PCM_RX_EN_CH3_MASK (1<<3) +#define M98504_PCM_RX_EN_CH3_SHIFT 3 +#define M98504_PCM_RX_EN_CH3_WIDTH 1 + +#define M98504_PCM_RX_EN_CH2_MASK (1<<2) +#define M98504_PCM_RX_EN_CH2_SHIFT 2 +#define M98504_PCM_RX_EN_CH2_WIDTH 1 + +#define M98504_PCM_RX_EN_CH1_MASK (1<<1) +#define M98504_PCM_RX_EN_CH1_SHIFT 1 +#define M98504_PCM_RX_EN_CH1_WIDTH 1 + +#define M98504_PCM_RX_EN_CH0_MASK (1<<0) +#define M98504_PCM_RX_EN_CH0_SHIFT 0 +#define M98504_PCM_RX_EN_CH0_WIDTH 1 + +/* MAX98504_REG_21_PCM_TX_ENABLES*/ +#define M98504_PCM_TX_EN_CH7_MASK (1<<7) +#define M98504_PCM_TX_EN_CH7_SHIFT 7 +#define M98504_PCM_TX_EN_CH7_WIDTH 1 + +#define M98504_PCM_TX_EN_CH6_MASK (1<<6) +#define M98504_PCM_TX_EN_CH6_SHIFT 6 +#define M98504_PCM_TX_EN_CH6_WIDTH 1 + +#define M98504_PCM_TX_EN_CH5_MASK (1<<5) +#define M98504_PCM_TX_EN_CH5_SHIFT 5 +#define M98504_PCM_TX_EN_CH5_WIDTH 1 + +#define M98504_PCM_TX_EN_CH4_MASK (1<<4) +#define M98504_PCM_TX_EN_CH4_SHIFT 4 +#define M98504_PCM_TX_EN_CH4_WIDTH 1 + +#define M98504_PCM_TX_EN_CH3_MASK (1<<3) +#define M98504_PCM_TX_EN_CH3_SHIFT 3 +#define M98504_PCM_TX_EN_CH3_WIDTH 1 + +#define M98504_PCM_TX_EN_CH2_MASK (1<<2) +#define M98504_PCM_TX_EN_CH2_SHIFT 2 +#define M98504_PCM_TX_EN_CH2_WIDTH 1 + +#define M98504_PCM_TX_EN_CH1_MASK (1<<1) +#define M98504_PCM_TX_EN_CH1_SHIFT 1 +#define M98504_PCM_TX_EN_CH1_WIDTH 1 + +#define M98504_PCM_TX_EN_CH0_MASK (1<<0) +#define M98504_PCM_TX_EN_CH0_SHIFT 0 +#define M98504_PCM_TX_EN_CH0_WIDTH 1 + +/* MAX98504_REG_22_PCM_TX_HIZ_CONTROL*/ +#define M98504_PCM_TX_HIZ_CTRL_CH7_MASK (1<<7) +#define M98504_PCM_TX_HIZ_CTRL_CH7_SHIFT 7 +#define M98504_PCM_TX_HIZ_CTRL_CH7_WIDTH 1 + +#define M98504_PCM_TX_HIZ_CTRL_CH6_MASK (1<<6) +#define M98504_PCM_TX_HIZ_CTRL_CH6_SHIFT 6 +#define M98504_PCM_TX_HIZ_CTRL_CH6_WIDTH 1 + +#define M98504_PCM_TX_HIZ_CTRL_CH5_MASK (1<<5) +#define M98504_PCM_TX_HIZ_CTRL_CH5_SHIFT 5 +#define M98504_PCM_TX_HIZ_CTRL_CH5_WIDTH 1 + +#define M98504_PCM_TX_HIZ_CTRL_CH4_MASK (1<<4) +#define M98504_PCM_TX_HIZ_CTRL_CH4_SHIFT 4 +#define M98504_PCM_TX_HIZ_CTRL_CH4_WIDTH 1 + +#define M98504_PCM_TX_HIZ_CTRL_CH3_MASK (1<<3) +#define M98504_PCM_TX_HIZ_CTRL_CH3_SHIFT 3 +#define M98504_PCM_TX_HIZ_CTRL_CH3_WIDTH 1 + +#define M98504_PCM_TX_HIZ_CTRL_CH2_MASK (1<<2) +#define M98504_PCM_TX_HIZ_CTRL_CH2_SHIFT 2 +#define M98504_PCM_TX_HIZ_CTRL_CH2_WIDTH 1 + +#define M98504_PCM_TX_HIZ_CTRL_CH1_MASK (1<<1) +#define M98504_PCM_TX_HIZ_CTRL_CH1_SHIFT 1 +#define M98504_PCM_TX_HIZ_CTRL_CH1_WIDTH 1 + +#define M98504_PCM_TX_HIZ_CTRL_CH0_MASK (1<<0) +#define M98504_PCM_TX_HIZ_CTRL_CH0_SHIFT 0 +#define M98504_PCM_TX_HIZ_CTRL_CH0_WIDTH 1 + +/* MAX98504_REG_23_PCM_TX_CHANNEL_SOURCES*/ +#define M98504_PCM_TX_SOURCE_CH7_MASK (1<<7) +#define M98504_PCM_TX_SOURCE_CH7_SHIFT 7 +#define M98504_PCM_TX_SOURCE_CH7_WIDTH 1 + +#define M98504_PCM_TX_SOURCE_CH6_MASK (1<<6) +#define M98504_PCM_TX_SOURCE_CH6_SHIFT 6 +#define M98504_PCM_TX_SOURCE_CH6_WIDTH 1 + +#define M98504_PCM_TX_SOURCE_CH5_MASK (1<<5) +#define M98504_PCM_TX_SOURCE_CH5_SHIFT 5 +#define M98504_PCM_TX_SOURCE_CH5_WIDTH 1 + +#define M98504_PCM_TX_SOURCE_CH4_MASK (1<<4) +#define M98504_PCM_TX_SOURCE_CH4_SHIFT 4 +#define M98504_PCM_TX_SOURCE_CH4_WIDTH 1 + +#define M98504_PCM_TX_SOURCE_CH3_MASK (1<<3) +#define M98504_PCM_TX_SOURCE_CH3_SHIFT 3 +#define M98504_PCM_TX_SOURCE_CH3_WIDTH 1 + +#define M98504_PCM_TX_SOURCE_CH2_MASK (1<<2) +#define M98504_PCM_TX_SOURCE_CH2_SHIFT 2 +#define M98504_PCM_TX_SOURCE_CH2_WIDTH 1 + +#define M98504_PCM_TX_SOURCE_CH1_MASK (1<<1) +#define M98504_PCM_TX_SOURCE_CH1_SHIFT 1 +#define M98504_PCM_TX_SOURCE_CH1_WIDTH 1 + +#define M98504_PCM_TX_SOURCE_CH0_MASK (1<<0) +#define M98504_PCM_TX_SOURCE_CH0_SHIFT 0 +#define M98504_PCM_TX_SOURCE_CH0_WIDTH 1 + +/* MAX98504_REG_24_PCM_MODE_CONFIG*/ +#define M98504_PCM_MODE_CFG_CH_SIZE_MASK (0x3<<6) +#define M98504_PCM_MODE_CFG_CH_SIZE_SHIFT 6 +#define M98504_PCM_MODE_CFG_CH_SIZE_WIDTH 2 + +#define M98504_PCM_MODE_CFG_CH_SIZE_8_MASK \ + (0<<M98504_PCM_MODE_CFG_CH_SIZE_SHIFT) +#define M98504_PCM_MODE_CFG_CH_SIZE_16_MASK \ + (1<<M98504_PCM_MODE_CFG_CH_SIZE_SHIFT) +#define M98504_PCM_MODE_CFG_CH_SIZE_24_MASK \ + (2<<M98504_PCM_MODE_CFG_CH_SIZE_SHIFT) +#define M98504_PCM_MODE_CFG_CH_SIZE_32_MASK \ + (3<<M98504_PCM_MODE_CFG_CH_SIZE_SHIFT) + +#define M98504_PCM_MODE_CFG_FORMAT_MASK (0x7<<3) +#define M98504_PCM_MODE_CFG_FORMAT_SHIFT 3 +#define M98504_PCM_MODE_CFG_FORMAT_WIDTH 3 + +#define M98504_PCM_MODE_CFG_FORMAT_I2S_MASK \ + (0<<M98504_PCM_MODE_CFG_FORMAT_SHIFT) +#define M98504_PCM_MODE_CFG_FORMAT_LJ_MASK \ + (1<<M98504_PCM_MODE_CFG_FORMAT_SHIFT) +#define M98504_PCM_MODE_CFG_FORMAT_RJ_MASK \ + (2<<M98504_PCM_MODE_CFG_FORMAT_SHIFT) +#define M98504_PCM_MODE_CFG_FORMAT_TDM_MODE1_MASK \ + (3<<M98504_PCM_MODE_CFG_FORMAT_SHIFT) +#define M98504_PCM_MODE_CFG_FORMAT_TDM_MODE2_MASK \ + (4<<M98504_PCM_MODE_CFG_FORMAT_SHIFT) + +#define M98504_PCM_MODE_CFG_BCLKEDGE_MASK (1<<2) +#define M98504_PCM_MODE_CFG_BCLKEDGE_SHIFT 2 +#define M98504_PCM_MODE_CFG_BCLKEDGE_WIDTH 1 + +#define M98504_PCM_MODE_CFG_CHSEL_MASK (1<<1) +#define M98504_PCM_MODE_CFG_CHSEL_SHIFT 1 +#define M98504_PCM_MODE_CFG_CHSEL_WIDTH 1 + +#define M98504_PCM_MODE_CFG_TX_EXTRA_HIZ_MASK (1<<0) +#define M98504_PCM_MODE_CFG_TX_EXTRA_HIZ_SHIFT 0 +#define M98504_PCM_MODE_CFG_TX_EXTRA_HIZ_WIDTH 1 + +/* MAX98504_REG_25_PCM_DSP_CONFIG*/ +#define M98504_PCM_DSP_CFG_TX_DITH_EN_MASK (1<<7) +#define M98504_PCM_DSP_CFG_TX_DITH_EN_SHIFT 7 +#define M98504_PCM_DSP_CFG_TX_DITH_EN_WIDTH 1 + +#define M98504_PCM_DSP_CFG_MEAS_DCBLK_EN_MASK (1<<6) +#define M98504_PCM_DSP_CFG_MEAS_DCBLK_EN_SHIFT 6 +#define M98504_PCM_DSP_CFG_MEAS_DCBLK_EN_WIDTH 1 + +#define M98504_PCM_DSP_CFG_RX_DITH_EN_MASK (1<<5) +#define M98504_PCM_DSP_CFG_RX_DITH_EN_SHIFT 5 +#define M98504_PCM_DSP_CFG_RX_DITH_EN_WIDTH 1 + +#define M98504_PCM_DSP_CFG_RX_FLT_MODE_MASK (1<<4) +#define M98504_PCM_DSP_CFG_RX_FLT_MODE_SHIFT 4 +#define M98504_PCM_DSP_CFG_RX_FLT_MODE_WIDTH 1 + +#define M98504_PCM_DSP_CFG_FLT_MASK (\ + M98504_PCM_DSP_CFG_TX_DITH_EN_MASK|\ + M98504_PCM_DSP_CFG_MEAS_DCBLK_EN_MASK|\ + M98504_PCM_DSP_CFG_RX_DITH_EN_MASK|\ + M98504_PCM_DSP_CFG_RX_FLT_MODE_MASK) +#define M98504_PCM_DSP_CFG_FLT_SHIFT 4 +#define M98504_PCM_DSP_CFG_FLT_WIDTH 4 + + +#define M98504_PCM_DSP_CFG_RX_GAIN_MASK (0xf<<0) +#define M98504_PCM_DSP_CFG_RX_GAIN_SHIFT 0 +#define M98504_PCM_DSP_CFG_RX_GAIN_WIDTH 4 + +/* MAX98504_REG_26_PCM_CLOCK_SETUP*/ +#define M98504_PCM_CLK_SETUP_BSEL_MASK (0xf<<0) +#define M98504_PCM_CLK_SETUP_BSEL_SHIFT 0 +#define M98504_PCM_CLK_SETUP_BSEL_WIDTH 4 + +#define M98094_PCM_CLK_SETUP_DAI_BSEL64 (1<<2) + +/* MAX98504_REG_27_PCM_SAMPLE_RATE_SETUP*/ +#define M98504_PCM_SR_SETUP_SPK_SR_MASK (0xf<<4) +#define M98504_PCM_SR_SETUP_SPK_SR_SHIFT 4 +#define M98504_PCM_SR_SETUP_SPK_SR_WIDTH 4 + +#define M98504_PCM_SR_SETUP_MEAS_SR_MASK (0xf<<0) +#define M98504_PCM_SR_SETUP_MEAS_SR_SHIFT 0 +#define M98504_PCM_SR_SETUP_MEAS_SR_WIDTH 4 + +/* MAX98504_REG_28_PCM_TO_SPEAKER_MONOMIX*/ +#define M98504_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3<<6) +#define M98504_PCM_TO_SPK_MONOMIX_CFG_SHIFT 6 +#define M98504_PCM_TO_SPK_MONOMIX_CFG_WIDTH 2 + +#define M98504_PCM_TO_SPK_MONOMIX_CH1_SRC_MASK (0x7<<3) +#define M98504_PCM_TO_SPK_MONOMIX_CH1_SRC_SHIFT 3 +#define M98504_PCM_TO_SPK_MONOMIX_CH1_SRC_WIDTH 3 + +#define M98504_PCM_TO_SPK_MONOMIX_CH0_SRC_MASK (0x7<<0) +#define M98504_PCM_TO_SPK_MONOMIX_CH0_SRC_SHIFT 0 +#define M98504_PCM_TO_SPK_MONOMIX_CH0_SRC_WIDTH 3 + +/* MAX98504_REG_30_PDM_TX_ENABLES*/ +#define M98504_PDM_EX_EN_CH1_MASK (1<<1) +#define M98504_PDM_EX_EN_CH1_SHIFT 1 +#define M98504_PDM_EX_EN_CH1_WIDTH 1 + +#define M98504_PDM_EX_EN_CH0_MASK (1<<0) +#define M98504_PDM_EX_EN_CH0_SHIFT 0 +#define M98504_PDM_EX_EN_CH0_WIDTH 1 + +/* MAX98504_REG_31_PDM_TX_HIZ_CONTROL*/ +#define M98504_PDM_EX_HIZ_CTRL_CH1_MASK (1<<1) +#define M98504_PDM_EX_HIZ_CTRL_CH1_SHIFT 1 +#define M98504_PDM_EX_HIZ_CTRL_CH1_WIDTH 1 + +#define M98504_PDM_EX_HIZ_CTRL_CH0_MASK (1<<0) +#define M98504_PDM_EX_HIZ_CTRL_CH0_SHIFT 0 +#define M98504_PDM_EX_HIZ_CTRL_CH0_WIDTH 1 + +/* MAX98504_REG_32_PDM_TX_CONTROL*/ +#define M98504_PDM_EX_CTRL_CH1_SRC_MASK (1<<1) +#define M98504_PDM_EX_CTRL_CH1_SRC_SHIFT 1 +#define M98504_PDM_EX_CTRL_CH1_SRC_WIDTH 1 + +#define M98504_PDM_EX_CTRL_CH0_SRC_MASK (1<<0) +#define M98504_PDM_EX_CTRL_CH0_SRC_SHIFT 0 +#define M98504_PDM_EX_CTRL_CH0_SRC_WIDTH 1 + +/* MAX98504_REG_33_PDM_RX_ENABLE*/ +#define M98504_PDM_RX_EN_MASK (1<<0) +#define M98504_PDM_RX_EN_SHIFT 0 +#define M98504_PDM_RX_EN_WIDTH 1 + +/* MAX98504_REG_34_SPEAKER_ENABLE*/ +#define M98504_SPK_EN_MASK (1<<0) +#define M98504_SPK_EN_SHIFT 0 +#define M98504_SPK_EN_WIDTH 1 + +/* MAX98504_REG_35_SPEAKER_SOURCE_SELECT*/ +#define M98504_SPK_SRC_SEL_MASK (0x3<<0) +#define M98504_SPK_SRC_SEL_SHIFT 0 +#define M98504_SPK_SRC_SEL_WIDTH 2 + +/* MAX98504_REG_36_MEASUREMENT_ENABLES*/ +#define M98504_MEAS_I_EN_MASK (1<<1) +#define M98504_MEAS_I_EN_SHIFT 1 +#define M98504_MEAS_I_EN_WIDTH 1 + +#define M98504_MEAS_V_EN_MASK (1<<0) +#define M98504_MEAS_V_EN_SHIFT 0 +#define M98504_MEAS_V_EN_WIDTH 1 + +/* MAX98504_REG_37_ANALOGUE_INPUT_GAIN*/ +#define M98504_ANALOG_INPUT_GAIN_MASK (1<<0) +#define M98504_ANALOG_INPUT_GAIN_SHIFT 0 +#define M98504_ANALOG_INPUT_GAIN_WIDTH 1 + +/* MAX98504_REG_38_TEMPERATURE_LIMIT_CONFIG*/ +#define M98504_TEMP_LIMIT_CFG_TEMPWARN_SEL_MASK (0x2<<2) +#define M98504_TEMP_LIMIT_CFG_TEMPWARN_SEL_SHIFT 2 +#define M98504_TEMP_LIMIT_CFG_TEMPWARN_SEL_WIDTH 2 + +#define M98504_TEMP_LIMIT_CFG_TEMP_SEL_MASK (0x2<<0) +#define M98504_TEMP_LIMIT_CFG_TEMP_SEL_SHIFT 0 +#define M98504_TEMP_LIMIT_CFG_TEMP_SEL_WIDTH 2 + +/* MAX98504_REG_39_ANALOGUE_SPARE*/ +#define M98504_ANALOG_SPARE_MASK (0xff<<0) +#define M98504_ANALOG_SPARE_SHIFT 0 +#define M98504_ANALOG_SPARE_WIDTH 8 + +/* MAX98504_REG_40_GLOBAL_ENABLE*/ +#define M98504_GLOBAL_EN_MASK (1<<0) +#define M98504_GLOBAL_EN_SHIFT 0 +#define M98504_GLOBAL_EN_WIDTH 1 + +/* MAX98504_REG_41_SOFTWARE_RESET*/ +#define M98504_SOFTWARE_RESET_MASK (1<<0) +#define M98504_SOFTWARE_RESET_SHIFT 0 +#define M98504_SOFTWARE_RESET_WIDTH 1 + +enum max98504_type { + MAX98504, +}; + +struct max98504_cdata { + unsigned int rate; + unsigned int fmt; +}; + +struct max98504_priv { + struct snd_soc_codec *codec; + struct regmap *regmap; + enum max98504_type devtype; + void *control_data; + struct max98504_pdata *pdata; + unsigned int sysclk; + struct max98504_cdata dai[1]; +#ifdef CONFIG_SND_SOC_MAXIM_DSM_A + struct class *dev_log_class; + struct device *dev_log; +#endif +}; + +#endif |