summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRavindra Lokhande <rlokhande@nvidia.com>2013-01-28 23:25:06 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:58:52 -0700
commitefd97c0dd3a11994e633e179e64a0a34eb2590b9 (patch)
treed79a5a0f3bb12e46ff567857f2cc3c2ef4cd309a
parentebd89da6f27a637443de3f15fcce5ef0a186ba88 (diff)
ASoC: Add max97236 driver
Add driver for max97236 audio amplifier driver. Change-Id: I7e62fa1bd6fee7fe57fde83ba649b288e784f145 Signed-off-by: Ravindra Lokhande <rlokhande@nvidia.com> Reviewed-on: http://git-master/r/194757 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Scott Peterson <speterson@nvidia.com> Reviewed-by: Gaurav Sarode <gsarode@nvidia.com>
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/max97236.c173
-rw-r--r--sound/soc/codecs/max97236.h300
4 files changed, 479 insertions, 0 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4079d66af0f7..2cf24f0647e6 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -51,6 +51,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9768 if I2C
select SND_SOC_MAX9877 if I2C
+ select SND_SOC_MAX97236 if I2C
select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C
select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
@@ -531,6 +532,9 @@ config SND_SOC_MAX9768
config SND_SOC_MAX9877
tristate
+config SND_SOC_MAX97236
+ tristate
+
config SND_SOC_MC13783
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f4ba144db193..484a10136e00 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -124,6 +124,7 @@ snd-soc-rt5640-objs := rt5640.o
# Amp
snd-soc-max9877-objs := max9877.o
+snd-soc-max97236-objs := max97236.o
snd-soc-tpa6130a2-objs := tpa6130a2.o
obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
@@ -251,4 +252,5 @@ obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
# Amp
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
+obj-$(CONFIG_SND_SOC_MAX97236) += snd-soc-max97236.o
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
diff --git a/sound/soc/codecs/max97236.c b/sound/soc/codecs/max97236.c
new file mode 100644
index 000000000000..8e1a5ebd002e
--- /dev/null
+++ b/sound/soc/codecs/max97236.c
@@ -0,0 +1,173 @@
+/*
+ * Max97236 Audio AMP driver
+ *
+ * Author: Ravindra Lokhande
+ * rlokhande@nvidia.com
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+
+#include "max97236.h"
+
+struct max97236 {
+ struct regmap *regmap;
+};
+
+static struct reg_default max97236_default_regs[] = {
+ { 0, 0x00 },
+ { 1, 0x00 },
+ { 2, 0x00 },
+ { 4, 0x00 },
+ { 5, 0x00 },
+ { 7, 0xC0 },
+ { 8, 0x40 },
+ { 9, 0x00 },
+ { 10, 0x00 },
+ { 11, 0x90 },
+ { 12, 0x00 },
+ { 13, 0x00 },
+ { 14, 0x00 },
+ { 15, 0x00 },
+ { 16, 0x00 },
+ { 17, 0x00 },
+ { 18, 0x00 },
+ { 19, 0x00 },
+ { 20, 0x00 },
+ { 21, 0x00 },
+ { 22, 0x00 },
+ { 23, 0x00 },
+ { 24, 0x00 },
+ { 25, 0x20 },
+ { 26, 0x05 },
+ { 29, 0x00 },
+ { 30, 0x00 },
+};
+
+static int max97236_probe(struct snd_soc_codec *codec)
+{
+ struct max97236 *max97236 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ codec->control_data = max97236->regmap;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+ if (ret)
+ return ret;
+
+ snd_soc_write(codec, M97236_REG_1D_ENABLE1, M97236_EN1_SHDN);
+ snd_soc_write(codec, M97236_REG_1E_ENABLE2, M97236_EN2_LFTEN |
+ M97236_EN2_RGHEN | M97236_EN2_FAST | 0x10);
+ snd_soc_write(codec, M97236_REG_07_LEFT_VOLUME, ((M97236_LVOL_L_EQ_R |
+ 0x39) & (~M97236_LVOL_MUTEL)));
+
+ return 0;
+}
+
+static const struct regmap_config max97236_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 31,
+ .reg_defaults = max97236_default_regs,
+ .num_reg_defaults = ARRAY_SIZE(max97236_default_regs),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_max97236 = {
+ .probe = max97236_probe,
+};
+
+static int __devinit max97236_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max97236 *max97236;
+ int err;
+
+ max97236 = devm_kzalloc(&i2c->dev, sizeof(*max97236), GFP_KERNEL);
+ if (!max97236)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, max97236);
+
+ max97236->regmap = regmap_init_i2c(i2c, &max97236_i2c_regmap_config);
+ if (IS_ERR(max97236->regmap)) {
+ err = PTR_ERR(max97236->regmap);
+ dev_err(&i2c->dev, "regmap_init() failed: %d\n", err);
+ return err;
+ }
+
+ err = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max97236,
+ NULL, 0);
+ if (err)
+ goto err_regmap_free;
+
+ return 0;
+
+ err_regmap_free:
+ regmap_exit(max97236->regmap);
+
+ return err;
+}
+
+static int __devexit max97236_i2c_remove(struct i2c_client *i2c)
+{
+ struct max97236 *max97236 = i2c_get_clientdata(i2c);
+
+ snd_soc_unregister_codec(&i2c->dev);
+ regmap_exit(max97236->regmap);
+
+ return 0;
+}
+
+static const struct i2c_device_id max97236_i2c_id[] = {
+ { "max97236", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max97236_i2c_id);
+
+static struct i2c_driver max97236_i2c_driver = {
+ .driver = {
+ .name = "max97236",
+ .owner = THIS_MODULE,
+ },
+ .probe = max97236_i2c_probe,
+ .remove = __devexit_p(max97236_i2c_remove),
+ .id_table = max97236_i2c_id,
+};
+
+static int __init max97236_init(void)
+{
+ return i2c_add_driver(&max97236_i2c_driver);
+}
+module_init(max97236_init);
+
+static void __exit max97236_exit(void)
+{
+ i2c_del_driver(&max97236_i2c_driver);
+}
+module_exit(max97236_exit);
+
+MODULE_AUTHOR("Ravindra Lokhande <rlokhande@nvidia.com>");
+MODULE_DESCRIPTION("max97236 amplifier driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max97236.h b/sound/soc/codecs/max97236.h
new file mode 100644
index 000000000000..4168a303c0b8
--- /dev/null
+++ b/sound/soc/codecs/max97236.h
@@ -0,0 +1,300 @@
+/*
+ * max97236.h - Header file for max97236 headphone amplifier
+ *
+ * Author: Ravindra Lokhande <rlokhande@nvidia.com>
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _MAX97236_H
+#define _MAX97236_H
+
+#include <linux/version.h>
+
+/*
+ * MAX97236 Register Definitions
+ */
+
+#define M97236_REG_00_STATUS1 0x00
+#define M97236_REG_01_STATUS2 0x01
+#define M97236_REG_02_STATUS3 0x02
+#define M97236_REG_03_FOR_EXPANSION 0x03
+#define M97236_REG_04_IRQ_MASK1 0x04
+#define M97236_REG_05_IRQ_MASK2 0x05
+#define M97236_REG_06_FOR_EXPANSION 0x06
+#define M97236_REG_07_LEFT_VOLUME 0x07
+#define M97236_REG_08_RIGHT_VOLUME 0x08
+#define M97236_REG_09_MICROPHONE 0x09
+#define M97236_REG_0A_FOR_EXPANSION 0x0A
+#define M97236_REG_0B_VENDOR_ID_REGSITER 0x0B
+#define M97236_REG_0C_FOR_EXPANSION 0x0C
+#define M97236_REG_0D_FOR_EXPANSION 0x0D
+#define M97236_REG_0E_FOR_EXPANSION 0x0E
+#define M97236_REG_0F_FOR_EXPANSION 0x0F
+#define M97236_REG_10_FOR_EXPANSION 0x10
+#define M97236_REG_11_FOR_EXPANSION 0x11
+#define M97236_REG_12_KEYSCAN_CLOCK_DIVIDER1 0x12
+#define M97236_REG_13_KEYSCAN_CLOCK_DIVIDER2 0x13
+#define M97236_REG_14_KEYSCAN_CLOCK_DIVIDER_ADC 0x14
+#define M97236_REG_15_KEYSCAN_DEBOUNCE 0x15
+#define M97236_REG_16_KEYSCAN_DELAY 0x16
+#define M97236_REG_17_PASSIVE_MBH_KEYSCAN_DATA 0x17
+#define M97236_REG_18_DC_TEST_SLEW_CONTROL 0x18
+#define M97236_REG_19_STATE_FORCING 0x19
+#define M97236_REG_1A_AC_TEST_CONTROL 0x1A
+#define M97236_REG_1B_FOR_EXPANSION 0x1B
+#define M97236_REG_1C_FOR_EXPANSION 0x1C
+#define M97236_REG_1D_ENABLE1 0x1D
+#define M97236_REG_1E_ENABLE2 0x1E
+
+/*
+ * M97236_REG_00_STATUS1
+ */
+#define M97236_ST1_JKIN_MASK (1<<7)
+#define M97236_ST1_JKIN_SHIFT 7
+#define M97236_ST1_JKIN_WIDTH 1
+#define M97236_ST1_DDONE_MASK (1<<6)
+#define M97236_ST1_DDONE_SHIFT 6
+#define M97236_ST1_DDONE_WIDTH 1
+#define M97236_ST1_VOL_MASK (1<<5)
+#define M97236_ST1_VOL_SHIFT 5
+#define M97236_ST1_VOL_WIDTH 1
+#define M97236_ST1_MIC_IN_MASK (1<<3)
+#define M97236_ST1_MIC_IN_SHIFT 3
+#define M97236_ST1_MIC_IN_WIDTH 1
+#define M97236_ST1_JACKSW_MASK (1<<2)
+#define M97236_ST1_JACKSW_SHIFT 2
+#define M97236_ST1_JACKSW_WIDTH 1
+#define M97236_ST1_MCSW_MASK (1<<1)
+#define M97236_ST1_MCSW_SHIFT 1
+#define M97236_ST1_MCSW_WIDTH 1
+#define M97236_ST1_MBH_MASK (1<<0)
+#define M97236_ST1_MBH_SHIFT 0
+#define M97236_ST1_MBH_WIDTH 1
+
+/*
+ * M97236_REG_01_STATUS2
+ */
+#define M97236_ST2_LINE_L_MASK (1<<7)
+#define M97236_ST2_LINE_L_SHIFT 7
+#define M97236_ST2_LINE_L_WIDTH 1
+#define M97236_ST2_LINE_R_MASK (1<<6)
+#define M97236_ST2_LINE_R_SHIFT 6
+#define M97236_ST2_LINE_R_WIDTH 1
+#define M97236_ST2_HP_L_MASK (1<<5)
+#define M97236_ST2_HP_L_SHIFT 5
+#define M97236_ST2_HP_L_WIDTH 1
+#define M97236_ST2_HP_R_MASK (1<<4)
+#define M97236_ST2_HP_R_SHIFT 4
+#define M97236_ST2_HP_R_WIDTH 1
+#define M97236_ST2_JACKSWINC_MASK (1<<3)
+#define M97236_ST2_JACKSWINC_SHIFT 3
+#define M97236_ST2_JACKSWINC_WIDTH 1
+#define M97236_ST2_KEY_MASK (1<<2)
+#define M97236_ST2_KEY_SHIFT 2
+#define M97236_ST2_KEY_WIDTH 1
+
+/*
+ * M97236_REG_02_STATUS3
+ */
+#define M97236_ST3_GND_MASK (0x3<<0)
+#define M97236_ST3_GND_SHIFT 0
+#define M97236_ST3_GND_WIDTH 2
+
+/*
+ * M97236_REG_04_IRQ_MASK1
+ */
+#define M97236_IRQ_1_IJKIN_MASK (1<<7)
+#define M97236_IRQ_1_IJKIN_SHIFT 7
+#define M97236_IRQ_1_IJKIN_WIDTH 1
+#define M97236_IRQ_1_IDDONE_MASK (1<<6)
+#define M97236_IRQ_1_IDDONE_SHIFT 6
+#define M97236_IRQ_1_IDDONE_WIDTH 1
+#define M97236_IRQ_1_IVOL_MASK (1<<5)
+#define M97236_IRQ_1_IVOL_SHIFT 5
+#define M97236_IRQ_1_IVOL_WIDTH 1
+#define M97236_IRQ_1_IMIC_MASK (1<<3)
+#define M97236_IRQ_1_IMIC_SHIFT 3
+#define M97236_IRQ_1_IMIC_WIDTH 1
+#define M97236_IRQ_1_JACKSW_MASK (1<<2)
+#define M97236_IRQ_1_JACKSW_SHIFT 2
+#define M97236_IRQ_1_JACKSW_WIDTH 1
+#define M97236_IRQ_1_IMCSW_MASK (1<<1)
+#define M97236_IRQ_1_IMCSW_SHIFT 1
+#define M97236_IRQ_1_IMCSW_WIDTH 1
+#define M97236_IRQ_1_IMBH_MASK (1<<0)
+#define M97236_IRQ_1_IMBH_SHIFT 0
+#define M97236_IRQ_1_IMBH_WIDTH 1
+
+/*
+ * M97236_REG_05_IRQ_MASK2
+ */
+#define M97236_IRQ_2_ILINE_L_MASK (1<<7)
+#define M97236_IRQ_2_ILINE_L_SHIFT 7
+#define M97236_IRQ_2_ILINE_L_WIDTH 1
+#define M97236_IRQ_2_ILINE_R_MASK (1<<6)
+#define M97236_IRQ_2_ILINE_R_SHIFT 6
+#define M97236_IRQ_2_ILINE_R_WIDTH 1
+#define M97236_IRQ_2_IHP_L_MASK (1<<5)
+#define M97236_IRQ_2_IHP_L_SHIFT 5
+#define M97236_IRQ_2_IHP_L_WIDTH 1
+#define M97236_IRQ_2_IHP_R_MASK (1<<4)
+#define M97236_IRQ_2_IHP_R_SHIFT 4
+#define M97236_IRQ_2_IHP_R_WIDTH 1
+#define M97236_IRQ_2_IJACKSW_MASK (1<<3)
+#define M97236_IRQ_2_IJACKSW_SHIFT 3
+#define M97236_IRQ_2_IJACKSW_WIDTH 1
+#define M97236_IRQ_2_IKEY_MASK (1<<2)
+#define M97236_IRQ_2_IKEY_SHIFT 2
+#define M97236_IRQ_2_IKEY_WIDTH 1
+
+/*
+ * M97236_REG_07_LEFT_VOLUME
+ */
+#define M97236_LVOL_L_EQ_R 0x80
+#define M97236_LVOL_L_EQ_R_MASK (1<<7)
+#define M97236_LVOL_L_EQ_R_SHIFT 7
+#define M97236_LVOL_L_EQ_R_WIDTH 1
+
+#define M97236_LVOL_MUTEL 0x40
+#define M97236_LVOL_MUTEL_MASK (1<<6)
+#define M97236_LVOL_MUTEL_SHIFT 6
+#define M97236_LVOL_MUTEL_WIDTH 1
+#define M97236_LVOL_LVOL_MASK (0x3F<<0)
+#define M97236_LVOL_LVOL_SHIFT 0
+#define M97236_LVOL_LVOL_WIDTH 6
+
+/*
+ * M97236_REG_08_RIGHT_VOLUME
+ */
+#define M97236_RVOL_MUTEL_MASK (1<<6)
+#define M97236_RVOL_MUTEL_SHIFT 6
+#define M97236_RVOL_MUTEL_WIDTH 1
+#define M97236_RVOL_RVOL_MASK (0x3F<<0)
+#define M97236_RVOL_RVOL_SHIFT 0
+#define M97236_RVOL_RVOL_WIDTH 6
+
+/*
+ * M97236_REG_09_MICROPHONE
+ */
+#define M97236_MIC_GAIN_MASK (1<<6)
+#define M97236_MIC_GAIN_SHIFT 6
+#define M97236_MIC_GAIN_WIDTH 1
+#define M97236_MIC_MICR_MASK (0x7<<3)
+#define M97236_MIC_MICR_SHIFT 3
+#define M97236_MIC_MICR_WIDTH 3
+#define M97236_MIC_BIAS_MASK (1<<2)
+#define M97236_MIC_BIAS_SHIFT 2
+#define M97236_MIC_BIAS_WIDTH 1
+
+/*
+ * M97236_REG_0B_VENDOR_ID_REGSITER
+ */
+#define M97236_VID_ID_MASK (0xF<<4)
+#define M97236_VID_ID_SHIFT 4
+#define M97236_VID_ID_WIDTH 4
+
+/*
+ * M97236_REG_19_STATE_FORCING
+ */
+#define M97236_ST_FORCEFORCE_MASK (1<<5)
+#define M97236_ST_FORCEFORCE_SHIFT 5
+#define M97236_ST_FORCEFORCE_WIDTH 1
+#define M97236_ST_FORCESTATE_MASK (0xF<<1)
+#define M97236_ST_FORCESTATE_SHIFT 1
+#define M97236_ST_FORCESTATE_WIDTH 4
+
+/*
+ * M97236_REG_1A_AC_TEST_CONTROL
+ */
+#define M97236_AC_TC_AC_REPEAT_MASK (0x3<<4)
+#define M97236_AC_TC_AC_REPEAT_SHIFT 4
+#define M97236_AC_TC_AC_REPEAT_WIDTH 2
+#define M97236_AC_TC_PULSE_WIDTH_MASK (0x3<<2)
+#define M97236_AC_TC_PULSE_WIDTH_SHIFT 2
+#define M97236_AC_TC_PULSE_WIDTH_WIDTH 2
+#define M97236_AC_TC_PULSE_AMP_MASK (0x3<<0)
+#define M97236_AC_TC_PULSE_AMP_SHIFT 0
+#define M97236_AC_TC_PULSE_AMP_WIDTH 2
+
+/*
+ * M97236_REG_1D_ENABLE1
+ */
+#define M97236_EN1_SHDN 0x80
+#define M97236_EN1_SHDN_MASK (1<<7)
+#define M97236_EN1_SHDN_SHIFT 7
+#define M97236_EN1_SHDN_WIDTH 1
+
+#define M97236_EN1_RESET 0x40
+#define M97236_EN1_RESET_MASK (1<<6)
+#define M97236_EN1_RESET_SHIFT 6
+#define M97236_EN1_RESET_WIDTH 1
+
+#define M97236_EN1_MIC_BIAS 0x10
+#define M97236_EN1_MIC_BIAS_MASK (1<<4)
+#define M97236_EN1_MIC_BIAS_SHIFT 4
+#define M97236_EN1_MIC_BIAS_WIDTH 1
+
+#define M97236_EN1_MIC_AMP 0x8
+#define M97236_EN1_MIC_AMP_MASK (1<<3)
+#define M97236_EN1_MIC_AMP_SHIFT 3
+#define M97236_EN1_MIC_AMP_WIDTH 1
+
+#define M97236_EN1_KS 0x4
+#define M97236_EN1_KS_MASK (1<<2)
+#define M97236_EN1_KS_SHIFT 2
+#define M97236_EN1_KS_WIDTH 1
+
+/*
+ * M97236_REG_1E_ENABLE2
+ */
+#define M97236_EN2_LFTEN 0x80
+#define M97236_EN2_LFTEN_MASK (1<<7)
+#define M97236_EN2_LFTEN_SHIFT 7
+#define M97236_EN2_LFTEN_WIDTH 1
+
+#define M97236_EN2_RGHEN 0x40
+#define M97236_EN2_RGHEN_MASK (1<<6)
+#define M97236_EN2_RGHEN_SHIFT 6
+#define M97236_EN2_RGHEN_WIDTH 1
+
+#define M97236_EN2_VSEN 0x20
+#define M97236_EN2_VSEN_MASK (1<<5)
+#define M97236_EN2_VSEN_SHIFT 5
+#define M97236_EN2_VSEN_WIDTH 1
+
+#define M97236_EN2_ZDEN 0x10
+#define M97236_EN2_ZDEN_MASK (1<<4)
+#define M97236_EN2_ZDEN_SHIFT 4
+#define M97236_EN2_ZDEN_WIDTH 1
+
+#define M97236_EN2_FAST 0x8
+#define M97236_EN2_FAST_MASK (1<<3)
+#define M97236_EN2_FAST_SHIFT 3
+#define M97236_EN2_FAST_WIDTH 1
+
+#define M97236_EN2_THRH 0x4
+#define M97236_EN2_THRH_MASK (1<<2)
+#define M97236_EN2_THRH_SHIFT 2
+#define M97236_EN2_THRH_WIDTH 1
+
+#define M97236_EN2_AUTO
+#define M97236_EN2_AUTO_MASK (0x3<<0)
+#define M97236_EN2_AUTO_SHIFT 0
+#define M97236_EN2_AUTO_WIDTH 2
+
+#endif