ASoC: wcd9xxx: Add device tree support in codec for I2C
Add device tree support for I2C mode in codec driver.
Parse I2C device information for codec from device tree
and enable power-supplies, gpio, MCLK configurations.
Change-Id: I070b7389d01b5cb14f2897e0cb75ebad72d432a7
Signed-off-by: Venkat Sudhir <vsudhir@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 96e3a61..090d8db 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -22,12 +22,14 @@
- qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
- qcom,cdc-micbias-cfilt2-mv - cfilt2 output voltage in milli volts.
- qcom,cdc-micbias-cfilt3-mv - cfilt3 output voltage in milli volts.
- cfilt volatge can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
+ cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
- qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1 (should be from 1 to 3).
- qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
- qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
- qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+ This value represents the connected CFLIT to MIC Bias.
+
- qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
- qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
- qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
@@ -88,3 +90,109 @@
qcom,cdc-slim-ifd = "taiko-slim-ifd";
qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 00 17 02];
};
+
+Wcd9xxx audio CODEC in I2C mode
+
+ - compatible = "qcom,wcd9xxx-i2c-device";
+ - reg: represents the slave address provided to the I2C driver.
+ - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
+ - <supply-name>-supply: phandle to the regulator device tree node.
+ - qcom,<supply-name>-voltage - specifies voltage levels for supply. Should be
+ specified in pairs (min, max), units mV.
+ - qcom,<supply-name>-current - specifies max current in mA that can drawn
+ from the <supply-name>.
+
+ above three properties with "supply-name" set to "qcom,cdc-vdd-buck", "qcom,cdc-vdd-tx-h",
+ "qcom,cdc-vdd-rx-h", "qcom,cdc-vddpx-1", "qcom,cdc-vdd-a-1p2v", "qcom,cdc-vddcx-1",
+ "qcom,cdc-vddcx-2" should be present.
+
+ - qcom,cdc-micbias-ldoh-v - LDOH output in volts ( should be 1.95 V and 3.00 V).
+
+ - qcom,cdc-micbias-cfilt1-mv - cfilt1 output voltage in milli volts.
+ - qcom,cdc-micbias-cfilt2-mv - cfilt2 output voltage in milli volts.
+ - qcom,cdc-micbias-cfilt3-mv - cfilt3 output voltage in milli volts.
+ cfilt voltage can be set to max of qcom,cdc-micbias-ldoh-v - 0.15V.
+
+ - qcom,cdc-micbias1-cfilt-sel = cfilt to use for micbias1 (should be from 1 to 3).
+ - qcom,cdc-micbias2-cfilt-sel = cfilt to use for micbias2 (should be from 1 to 3).
+ - qcom,cdc-micbias3-cfilt-sel = cfilt to use for micbias3 (should be from 1 to 3).
+ - qcom,cdc-micbias4-cfilt-sel = cfilt to use for micbias4 (should be from 1 to 3).
+ This value represents the connected CFLIT to MIC Bias.
+
+ - qcom,cdc-micbias1-ext-cap: Boolean. Enable micbias 1 external capacitor mode.
+ - qcom,cdc-micbias2-ext-cap: Boolean. Enable micbias 2 external capacitor mode.
+ - qcom,cdc-micbias3-ext-cap: Boolean. Enable micbias 3 external capacitor mode.
+ - qcom,cdc-micbias4-ext-cap: Boolean. Enable micbias 4 external capacitor mode.
+
+Example:
+i2c@f9925000 {
+ cell-index = <3>;
+ compatible = "qcom,i2c-qup";
+ reg = <0xf9925000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 97 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <24000000>;
+
+ wcd9xxx_codec@0d{
+ compatible = "qcom,wcd9xxx-i2c";
+ reg = <0x0d>;
+ qcom,cdc-reset-gpio = <&msmgpio 22 0>;
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+
+ cdc-vdd-buck-supply = <&pm8019_l11>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <25000>;
+
+ cdc-vdd-tx-h-supply = <&pm8019_l11>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pm8019_l11>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pm8019_l11>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+
+ cdc-vdd-a-1p2v-supply = <&pm8019_l9>;
+ qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
+ qcom,cdc-vdd-a-1p2v-current = <10000>;
+
+ cdc-vddcx-1-supply = <&pm8019_l9>;
+ qcom,cdc-vddcx-1-voltage = <1200000 1200000>;
+ qcom,cdc-vddcx-1-current = <10000>;
+
+ cdc-vddcx-2-supply = <&pm8019_l9>;
+ qcom,cdc-vddcx-2-voltage = <1200000 1200000>;
+ qcom,cdc-vddcx-2-current = <10000>;
+
+ qcom,cdc-micbias-ldoh-v = <0x3>;
+ qcom,cdc-micbias-cfilt1-mv = <1800>;
+ qcom,cdc-micbias-cfilt2-mv = <2700>;
+ qcom,cdc-micbias-cfilt3-mv = <1800>;
+ qcom,cdc-micbias1-cfilt-sel = <0x0>;
+ qcom,cdc-micbias2-cfilt-sel = <0x1>;
+ qcom,cdc-micbias3-cfilt-sel = <0x2>;
+ qcom,cdc-micbias4-cfilt-sel = <0x2>;
+ };
+
+ wcd9xxx_codec@77{
+ compatible = "qcom,wcd9xxx-i2c";
+ reg = <0x77>;
+ };
+
+ wcd9xxx_codec@66{
+ compatible = "qcom,wcd9xxx-i2c";
+ reg = <0x66>;
+ };
+ wcd9xxx_codec@55{
+ compatible = "qcom,wcd9xxx-i2c";
+ reg = <0x55>;
+ };
+};
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 1f7b67a..fa7c116 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -35,6 +35,8 @@
#define MAX_WCD9XXX_DEVICE 4
#define TABLA_I2C_MODE 0x03
#define SITAR_I2C_MODE 0x01
+#define CODEC_DT_MAX_PROP_SIZE 40
+#define WCD9XXX_I2C_GSBI_SLAVE_ID "3-000d"
struct wcd9xxx_i2c {
struct i2c_client *client;
@@ -43,6 +45,17 @@
int mod_id;
};
+static char *taiko_supplies[] = {
+ "cdc-vdd-buck", "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
+ "cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
+};
+
+static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
+ struct wcd9xxx_regulator *vreg, const char *vreg_name);
+static int wcd9xxx_dt_parse_micbias_info(struct device *dev,
+ struct wcd9xxx_micbias_setting *micbias);
+static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev);
+
struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
static int wcd9xxx_intf = -1;
@@ -764,19 +777,31 @@
int ret = 0;
int i2c_mode = 0;
static int device_id;
+ struct device *dev;
pr_info("%s\n", __func__);
if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
- pr_info("tabla card is already detected in slimbus mode\n");
+ dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n",
+ __func__);
return -ENODEV;
}
- pdata = client->dev.platform_data;
if (device_id > 0) {
wcd9xxx_modules[device_id++].client = client;
- pr_info("probe for other slaves devices of tabla\n");
+ dev_dbg(&client->dev, "%s:probe for other slaves\n"
+ "devices of codec\n", __func__);
return ret;
}
-
+ dev = &client->dev;
+ if (client->dev.of_node) {
+ dev_dbg(&client->dev, "%s:Platform data from device tree\n",
+ __func__);
+ pdata = wcd9xxx_populate_dt_pdata(&client->dev);
+ client->dev.platform_data = pdata;
+ } else {
+ dev_dbg(&client->dev, "%s:Platform data from board file\n",
+ __func__);
+ pdata = client->dev.platform_data;
+ }
wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
if (wcd9xxx == NULL) {
pr_err("%s: error, allocation failed\n", __func__);
@@ -858,7 +883,6 @@
return 0;
}
-#define CODEC_DT_MAX_PROP_SIZE 40
static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
struct wcd9xxx_regulator *vreg, const char *vreg_name)
{
@@ -1057,11 +1081,6 @@
return 0;
}
-static char *taiko_supplies[] = {
- "cdc-vdd-buck", "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
- "cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
-};
-
static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
{
struct wcd9xxx_pdata *pdata;
@@ -1071,12 +1090,11 @@
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
- dev_err(dev,
- "could not allocate memory for platform data\n");
+ dev_err(dev, "could not allocate memory for platform data\n");
return NULL;
}
-
- if (!strcmp(dev_name(dev), "taiko-slim-pgd")) {
+ if (!strcmp(dev_name(dev), "taiko-slim-pgd") ||
+ (!strcmp(dev_name(dev), WCD9XXX_I2C_GSBI_SLAVE_ID))) {
codec_supplies = taiko_supplies;
num_of_supplies = ARRAY_SIZE(taiko_supplies);
} else {
@@ -1111,11 +1129,7 @@
pdata->reset_gpio);
goto err;
}
-
- ret = wcd9xxx_dt_parse_slim_interface_dev_info(dev,
- &pdata->slimbus_slave_device);
- if (ret)
- goto err;
+ dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
return pdata;
err:
devm_kfree(dev, pdata);
@@ -1151,6 +1165,14 @@
if (slim->dev.of_node) {
dev_info(&slim->dev, "Platform data from device tree\n");
pdata = wcd9xxx_populate_dt_pdata(&slim->dev);
+ ret = wcd9xxx_dt_parse_slim_interface_dev_info(&slim->dev,
+ &pdata->slimbus_slave_device);
+ if (ret) {
+ dev_err(&slim->dev, "Error, parsing slim interface\n");
+ devm_kfree(&slim->dev, pdata);
+ ret = -EINVAL;
+ goto err;
+ }
slim->dev.platform_data = pdata;
} else {
@@ -1460,6 +1482,14 @@
#define WCD9XXX_I2C_DIGITAL_1 2
#define WCD9XXX_I2C_DIGITAL_2 3
+static struct i2c_device_id wcd9xxx_id_table[] = {
+ {"wcd9xxx-i2c", WCD9XXX_I2C_TOP_LEVEL},
+ {"wcd9xxx-i2c", WCD9XXX_I2C_ANALOG},
+ {"wcd9xxx-i2c", WCD9XXX_I2C_DIGITAL_1},
+ {"wcd9xxx-i2c", WCD9XXX_I2C_DIGITAL_2},
+ {}
+};
+
static struct i2c_device_id tabla_id_table[] = {
{"tabla top level", WCD9XXX_I2C_TOP_LEVEL},
{"tabla analog", WCD9XXX_I2C_ANALOG},
@@ -1481,9 +1511,22 @@
.suspend = wcd9xxx_i2c_suspend,
};
+static struct i2c_driver wcd9xxx_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "wcd9xxx-i2c-core",
+ },
+ .id_table = wcd9xxx_id_table,
+ .probe = wcd9xxx_i2c_probe,
+ .remove = __devexit_p(wcd9xxx_i2c_remove),
+ .resume = wcd9xxx_i2c_resume,
+ .suspend = wcd9xxx_i2c_suspend,
+};
+
+
static int __init wcd9xxx_init(void)
{
- int ret1, ret2, ret3, ret4, ret5, ret6;
+ int ret1, ret2, ret3, ret4, ret5, ret6, ret7;
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
@@ -1495,7 +1538,7 @@
ret3 = i2c_add_driver(&tabla_i2c_driver);
if (ret3 != 0)
- pr_err("failed to add the I2C driver\n");
+ pr_err("failed to add the tabla2x I2C driver\n");
ret4 = slim_driver_register(&sitar_slim_driver);
if (ret4 != 0)
@@ -1509,7 +1552,11 @@
if (ret6 != 0)
pr_err("Failed to register taiko SB driver: %d\n", ret6);
- return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
+ ret7 = i2c_add_driver(&wcd9xxx_i2c_driver);
+ if (ret7 != 0)
+ pr_err("failed to add the wcd9xxx I2C driver\n");
+
+ return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6 && ret7) ? -1 : 0;
}
module_init(wcd9xxx_init);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index ed414d4..8fdf4f2 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -45,7 +45,8 @@
#define TAIKO_TX_PORT_NUMBER 16
#define TAIKO_I2S_MASTER_MODE_MASK 0x08
-
+#define TAIKO_MCLK_CLK_12P288MHZ 12288000
+#define TAIKO_MCLK_CLK_9P6HZ 9600000
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -1538,45 +1539,50 @@
return -EINVAL;
}
}
- switch (dai_id) {
- case AIF1_CAP:
- case AIF2_CAP:
- case AIF3_CAP:
- /* only add to the list if value not set
- */
- if (enable && !(widget->value & 1 << port_id)) {
- if (wcd9xxx_tx_vport_validation(
+ if (taiko_p->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ switch (dai_id) {
+ case AIF1_CAP:
+ case AIF2_CAP:
+ case AIF3_CAP:
+ /* only add to the list if value not set
+ */
+ if (enable && !(widget->value & 1 << port_id)) {
+ if (wcd9xxx_tx_vport_validation(
vport_check_table[dai_id],
port_id,
taiko_p->dai)) {
- pr_info("%s: TX%u is used by other virtual port\n",
- __func__, port_id + 1);
- mutex_unlock(&codec->mutex);
- return -EINVAL;
- }
- widget->value |= 1 << port_id;
- list_add_tail(&core->tx_chs[port_id].list,
+ pr_debug("%s: TX%u is used by other\n"
+ "virtual port\n",
+ __func__, port_id + 1);
+ mutex_unlock(&codec->mutex);
+ return -EINVAL;
+ }
+ widget->value |= 1 << port_id;
+ list_add_tail(&core->tx_chs[port_id].list,
&taiko_p->dai[dai_id].wcd9xxx_ch_list
- );
- } else if (!enable && (widget->value & 1 << port_id)) {
- widget->value &= ~(1 << port_id);
- list_del_init(&core->tx_chs[port_id].list);
- } else {
- if (enable)
- pr_info("%s: TX%u port is used by this virtual port\n",
- __func__, port_id + 1);
- else
- pr_info("%s: TX%u port is not used by this virtual port\n",
- __func__, port_id + 1);
- /* avoid update power function */
+ );
+ } else if (!enable && (widget->value & 1 << port_id)) {
+ widget->value &= ~(1 << port_id);
+ list_del_init(&core->tx_chs[port_id].list);
+ } else {
+ if (enable)
+ pr_debug("%s: TX%u port is used by\n"
+ "this virtual port\n",
+ __func__, port_id + 1);
+ else
+ pr_debug("%s: TX%u port is not used by\n"
+ "this virtual port\n",
+ __func__, port_id + 1);
+ /* avoid update power function */
+ mutex_unlock(&codec->mutex);
+ return 0;
+ }
+ break;
+ default:
+ pr_err("Unknown AIF %d\n", dai_id);
mutex_unlock(&codec->mutex);
- return 0;
+ return -EINVAL;
}
- break;
- default:
- pr_err("Unknown AIF %d\n", dai_id);
- mutex_unlock(&codec->mutex);
- return -EINVAL;
}
pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
widget->name, widget->sname, widget->value, widget->shift);
@@ -2438,10 +2444,10 @@
{"SLIM RX3", NULL, "RX_I2S_CLK"},
{"SLIM RX4", NULL, "RX_I2S_CLK"},
- {"SLIM TX7", NULL, "TX_I2S_CLK"},
- {"SLIM TX8", NULL, "TX_I2S_CLK"},
- {"SLIM TX9", NULL, "TX_I2S_CLK"},
- {"SLIM TX10", NULL, "TX_I2S_CLK"},
+ {"SLIM TX7 MUX", NULL, "TX_I2S_CLK"},
+ {"SLIM TX8 MUX", NULL, "TX_I2S_CLK"},
+ {"SLIM TX9 MUX", NULL, "TX_I2S_CLK"},
+ {"SLIM TX10 MUX", NULL, "TX_I2S_CLK"},
};
static const struct snd_soc_dapm_route audio_map[] = {
@@ -3101,7 +3107,11 @@
static int taiko_set_dai_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
- pr_debug("%s\n", __func__);
+ struct snd_soc_codec *codec = dai->codec;
+ if (freq == TAIKO_MCLK_CLK_12P288MHZ)
+ snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x04);
+ else if (freq == TAIKO_MCLK_CLK_9P6HZ)
+ snd_soc_write(codec, TAIKO_A_CHIP_CTL, 0x0A);
return 0;
}
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index 7bc5a57..1fff80c 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -23,6 +23,7 @@
#define TAIKO_CACHE_SIZE TAIKO_NUM_REGISTERS
#define TAIKO_REG_VAL(reg, val) {reg, 0, val}
+#define TAIKO_MCLK_ID 0
extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
extern const u8 taiko_reset_reg_defaults[TAIKO_CACHE_SIZE];