|
@@ -47,6 +47,9 @@
|
|
|
#include <linux/i2c.h>
|
|
|
#include <linux/i2c/twl.h>
|
|
|
|
|
|
+/* Register descriptions for audio */
|
|
|
+#include <linux/mfd/twl4030-audio.h>
|
|
|
+
|
|
|
#include "twl-core.h"
|
|
|
|
|
|
/*
|
|
@@ -200,6 +203,105 @@ static struct twl_mapping twl4030_map[] = {
|
|
|
{ 2, TWL5031_BASEADD_INTERRUPTS },
|
|
|
};
|
|
|
|
|
|
+static struct reg_default twl4030_49_defaults[] = {
|
|
|
+ /* Audio Registers */
|
|
|
+ { 0x01, 0x00}, /* CODEC_MODE */
|
|
|
+ { 0x02, 0x00}, /* OPTION */
|
|
|
+ /* 0x03 Unused */
|
|
|
+ { 0x04, 0x00}, /* MICBIAS_CTL */
|
|
|
+ { 0x05, 0x00}, /* ANAMICL */
|
|
|
+ { 0x06, 0x00}, /* ANAMICR */
|
|
|
+ { 0x07, 0x00}, /* AVADC_CTL */
|
|
|
+ { 0x08, 0x00}, /* ADCMICSEL */
|
|
|
+ { 0x09, 0x00}, /* DIGMIXING */
|
|
|
+ { 0x0a, 0x0f}, /* ATXL1PGA */
|
|
|
+ { 0x0b, 0x0f}, /* ATXR1PGA */
|
|
|
+ { 0x0c, 0x0f}, /* AVTXL2PGA */
|
|
|
+ { 0x0d, 0x0f}, /* AVTXR2PGA */
|
|
|
+ { 0x0e, 0x00}, /* AUDIO_IF */
|
|
|
+ { 0x0f, 0x00}, /* VOICE_IF */
|
|
|
+ { 0x10, 0x3f}, /* ARXR1PGA */
|
|
|
+ { 0x11, 0x3f}, /* ARXL1PGA */
|
|
|
+ { 0x12, 0x3f}, /* ARXR2PGA */
|
|
|
+ { 0x13, 0x3f}, /* ARXL2PGA */
|
|
|
+ { 0x14, 0x25}, /* VRXPGA */
|
|
|
+ { 0x15, 0x00}, /* VSTPGA */
|
|
|
+ { 0x16, 0x00}, /* VRX2ARXPGA */
|
|
|
+ { 0x17, 0x00}, /* AVDAC_CTL */
|
|
|
+ { 0x18, 0x00}, /* ARX2VTXPGA */
|
|
|
+ { 0x19, 0x32}, /* ARXL1_APGA_CTL*/
|
|
|
+ { 0x1a, 0x32}, /* ARXR1_APGA_CTL*/
|
|
|
+ { 0x1b, 0x32}, /* ARXL2_APGA_CTL*/
|
|
|
+ { 0x1c, 0x32}, /* ARXR2_APGA_CTL*/
|
|
|
+ { 0x1d, 0x00}, /* ATX2ARXPGA */
|
|
|
+ { 0x1e, 0x00}, /* BT_IF */
|
|
|
+ { 0x1f, 0x55}, /* BTPGA */
|
|
|
+ { 0x20, 0x00}, /* BTSTPGA */
|
|
|
+ { 0x21, 0x00}, /* EAR_CTL */
|
|
|
+ { 0x22, 0x00}, /* HS_SEL */
|
|
|
+ { 0x23, 0x00}, /* HS_GAIN_SET */
|
|
|
+ { 0x24, 0x00}, /* HS_POPN_SET */
|
|
|
+ { 0x25, 0x00}, /* PREDL_CTL */
|
|
|
+ { 0x26, 0x00}, /* PREDR_CTL */
|
|
|
+ { 0x27, 0x00}, /* PRECKL_CTL */
|
|
|
+ { 0x28, 0x00}, /* PRECKR_CTL */
|
|
|
+ { 0x29, 0x00}, /* HFL_CTL */
|
|
|
+ { 0x2a, 0x00}, /* HFR_CTL */
|
|
|
+ { 0x2b, 0x05}, /* ALC_CTL */
|
|
|
+ { 0x2c, 0x00}, /* ALC_SET1 */
|
|
|
+ { 0x2d, 0x00}, /* ALC_SET2 */
|
|
|
+ { 0x2e, 0x00}, /* BOOST_CTL */
|
|
|
+ { 0x2f, 0x00}, /* SOFTVOL_CTL */
|
|
|
+ { 0x30, 0x13}, /* DTMF_FREQSEL */
|
|
|
+ { 0x31, 0x00}, /* DTMF_TONEXT1H */
|
|
|
+ { 0x32, 0x00}, /* DTMF_TONEXT1L */
|
|
|
+ { 0x33, 0x00}, /* DTMF_TONEXT2H */
|
|
|
+ { 0x34, 0x00}, /* DTMF_TONEXT2L */
|
|
|
+ { 0x35, 0x79}, /* DTMF_TONOFF */
|
|
|
+ { 0x36, 0x11}, /* DTMF_WANONOFF */
|
|
|
+ { 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */
|
|
|
+ { 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */
|
|
|
+ { 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */
|
|
|
+ { 0x3a, 0x06}, /* APLL_CTL */
|
|
|
+ { 0x3b, 0x00}, /* DTMF_CTL */
|
|
|
+ { 0x3c, 0x44}, /* DTMF_PGA_CTL2 (0x3C) */
|
|
|
+ { 0x3d, 0x69}, /* DTMF_PGA_CTL1 (0x3D) */
|
|
|
+ { 0x3e, 0x00}, /* MISC_SET_1 */
|
|
|
+ { 0x3f, 0x00}, /* PCMBTMUX */
|
|
|
+ /* 0x40 - 0x42 Unused */
|
|
|
+ { 0x43, 0x00}, /* RX_PATH_SEL */
|
|
|
+ { 0x44, 0x32}, /* VDL_APGA_CTL */
|
|
|
+ { 0x45, 0x00}, /* VIBRA_CTL */
|
|
|
+ { 0x46, 0x00}, /* VIBRA_SET */
|
|
|
+ { 0x47, 0x00}, /* VIBRA_PWM_SET */
|
|
|
+ { 0x48, 0x00}, /* ANAMIC_GAIN */
|
|
|
+ { 0x49, 0x00}, /* MISC_SET_2 */
|
|
|
+ /* End of Audio Registers */
|
|
|
+};
|
|
|
+
|
|
|
+static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg)
|
|
|
+{
|
|
|
+ switch (reg) {
|
|
|
+ case 0:
|
|
|
+ case 3:
|
|
|
+ case 40:
|
|
|
+ case 41:
|
|
|
+ case 42:
|
|
|
+ return false;
|
|
|
+ default:
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static const struct regmap_range twl4030_49_volatile_ranges[] = {
|
|
|
+ regmap_reg_range(TWL4030_BASEADD_TEST, 0xff),
|
|
|
+};
|
|
|
+
|
|
|
+static const struct regmap_access_table twl4030_49_volatile_table = {
|
|
|
+ .yes_ranges = twl4030_49_volatile_ranges,
|
|
|
+ .n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges),
|
|
|
+};
|
|
|
+
|
|
|
static struct regmap_config twl4030_regmap_config[4] = {
|
|
|
{
|
|
|
/* Address 0x48 */
|
|
@@ -212,6 +314,15 @@ static struct regmap_config twl4030_regmap_config[4] = {
|
|
|
.reg_bits = 8,
|
|
|
.val_bits = 8,
|
|
|
.max_register = 0xff,
|
|
|
+
|
|
|
+ .readable_reg = twl4030_49_nop_reg,
|
|
|
+ .writeable_reg = twl4030_49_nop_reg,
|
|
|
+
|
|
|
+ .volatile_table = &twl4030_49_volatile_table,
|
|
|
+
|
|
|
+ .reg_defaults = twl4030_49_defaults,
|
|
|
+ .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults),
|
|
|
+ .cache_type = REGCACHE_RBTREE,
|
|
|
},
|
|
|
{
|
|
|
/* Address 0x4a */
|
|
@@ -302,35 +413,50 @@ unsigned int twl_rev(void)
|
|
|
EXPORT_SYMBOL(twl_rev);
|
|
|
|
|
|
/**
|
|
|
- * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
|
|
|
+ * twl_get_regmap - Get the regmap associated with the given module
|
|
|
* @mod_no: module number
|
|
|
- * @value: an array of num_bytes+1 containing data to write
|
|
|
- * @reg: register address (just offset will do)
|
|
|
- * @num_bytes: number of bytes to transfer
|
|
|
*
|
|
|
- * Returns the result of operation - 0 is success
|
|
|
+ * Returns the regmap pointer or NULL in case of failure.
|
|
|
*/
|
|
|
-int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
|
|
+static struct regmap *twl_get_regmap(u8 mod_no)
|
|
|
{
|
|
|
- int ret;
|
|
|
int sid;
|
|
|
struct twl_client *twl;
|
|
|
|
|
|
if (unlikely(!twl_priv || !twl_priv->ready)) {
|
|
|
pr_err("%s: not initialized\n", DRIVER_NAME);
|
|
|
- return -EPERM;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
if (unlikely(mod_no >= twl_get_last_module())) {
|
|
|
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
|
|
|
- return -EPERM;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
sid = twl_priv->twl_map[mod_no].sid;
|
|
|
twl = &twl_priv->twl_modules[sid];
|
|
|
|
|
|
- ret = regmap_bulk_write(twl->regmap,
|
|
|
- twl_priv->twl_map[mod_no].base + reg, value,
|
|
|
- num_bytes);
|
|
|
+ return twl->regmap;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
|
|
|
+ * @mod_no: module number
|
|
|
+ * @value: an array of num_bytes+1 containing data to write
|
|
|
+ * @reg: register address (just offset will do)
|
|
|
+ * @num_bytes: number of bytes to transfer
|
|
|
+ *
|
|
|
+ * Returns the result of operation - 0 is success
|
|
|
+ */
|
|
|
+int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
|
|
+{
|
|
|
+ struct regmap *regmap = twl_get_regmap(mod_no);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!regmap)
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg,
|
|
|
+ value, num_bytes);
|
|
|
|
|
|
if (ret)
|
|
|
pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n",
|
|
@@ -351,25 +477,14 @@ EXPORT_SYMBOL(twl_i2c_write);
|
|
|
*/
|
|
|
int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
|
|
{
|
|
|
+ struct regmap *regmap = twl_get_regmap(mod_no);
|
|
|
int ret;
|
|
|
- int sid;
|
|
|
- struct twl_client *twl;
|
|
|
|
|
|
- if (unlikely(!twl_priv || !twl_priv->ready)) {
|
|
|
- pr_err("%s: not initialized\n", DRIVER_NAME);
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
- if (unlikely(mod_no >= twl_get_last_module())) {
|
|
|
- pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
|
|
|
+ if (!regmap)
|
|
|
return -EPERM;
|
|
|
- }
|
|
|
-
|
|
|
- sid = twl_priv->twl_map[mod_no].sid;
|
|
|
- twl = &twl_priv->twl_modules[sid];
|
|
|
|
|
|
- ret = regmap_bulk_read(twl->regmap,
|
|
|
- twl_priv->twl_map[mod_no].base + reg, value,
|
|
|
- num_bytes);
|
|
|
+ ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg,
|
|
|
+ value, num_bytes);
|
|
|
|
|
|
if (ret)
|
|
|
pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n",
|
|
@@ -379,6 +494,27 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
|
|
|
}
|
|
|
EXPORT_SYMBOL(twl_i2c_read);
|
|
|
|
|
|
+/**
|
|
|
+ * twl_regcache_bypass - Configure the regcache bypass for the regmap associated
|
|
|
+ * with the module
|
|
|
+ * @mod_no: module number
|
|
|
+ * @enable: Regcache bypass state
|
|
|
+ *
|
|
|
+ * Returns 0 else failure.
|
|
|
+ */
|
|
|
+int twl_set_regcache_bypass(u8 mod_no, bool enable)
|
|
|
+{
|
|
|
+ struct regmap *regmap = twl_get_regmap(mod_no);
|
|
|
+
|
|
|
+ if (!regmap)
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ regcache_cache_bypass(regmap, enable);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(twl_set_regcache_bypass);
|
|
|
+
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|