summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xDocumentation/devicetree/bindings/sound/qcom-audio-dev.txt4
-rw-r--r--drivers/mfd/Kconfig24
-rw-r--r--drivers/mfd/Makefile7
-rw-r--r--drivers/mfd/msm-cdc-supply.c458
-rw-r--r--drivers/mfd/wcd-gpio-ctrl.c188
-rw-r--r--drivers/mfd/wcd9330-regmap.c3
-rw-r--r--drivers/mfd/wcd9335-regmap.c1
-rw-r--r--drivers/mfd/wcd9xxx-core-resource.c197
-rw-r--r--drivers/mfd/wcd9xxx-core.c2417
-rw-r--r--drivers/mfd/wcd9xxx-irq.c48
-rw-r--r--drivers/mfd/wcd9xxx-slimslave.c4
-rw-r--r--drivers/mfd/wcd9xxx-utils.c1147
-rw-r--r--include/linux/mfd/msm-cdc-supply.h48
-rwxr-xr-xinclude/linux/mfd/wcd9xxx/core-resource.h153
-rw-r--r--[-rwxr-xr-x]include/linux/mfd/wcd9xxx/core.h170
-rwxr-xr-xinclude/linux/mfd/wcd9xxx/pdata.h9
-rw-r--r--include/linux/mfd/wcd9xxx/wcd-gpio-ctrl.h34
-rw-r--r--include/linux/mfd/wcd9xxx/wcd9xxx-irq.h32
-rw-r--r--include/linux/mfd/wcd9xxx/wcd9xxx-utils.h119
-rwxr-xr-xsound/soc/codecs/Kconfig1
-rw-r--r--sound/soc/codecs/wcd9330.c156
-rwxr-xr-xsound/soc/codecs/wcd9335.c333
-rw-r--r--sound/soc/codecs/wcd9335.h38
-rw-r--r--sound/soc/codecs/wcd9xxx-mbhc.c4
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.c40
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.h4
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr.h4
-rw-r--r--sound/soc/codecs/wcd_cpe_core.c2
-rw-r--r--sound/soc/codecs/wcd_cpe_core.h6
29 files changed, 2773 insertions, 2878 deletions
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index ff31419c5814..8fd124123e27 100755
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -354,7 +354,7 @@ Required properties:
Required properties:
- - compatible : "qcom,wcd-gpio-ctrl"
+ - compatible : "qcom,msm-cdc-pinctrl"
- qcom,cdc-rst-n-gpio : TLMM GPIO number
@@ -625,7 +625,7 @@ Example:
};
wcd_gpio_ctrl {
- compatible = "qcom,wcd-gpio-ctrl";
+ compatible = "qcom,msm-cdc-pinctrl";
qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
pinctrl-names = "aud_active", "aud_sleep";
pinctrl-0 = <&cdc_reset_active>;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0140c727e44d..6622ef8f45bb 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1516,10 +1516,29 @@ config MSM_CDC_PINCTRL
This driver acts as interface between codec and pinctrl
framework.
+config MSM_CDC_SUPPLY
+ tristate "MSM Codec Power Supply"
+ help
+ Enables msm codec power supply driver. The power supply
+ driver provides API support for handling WCD and WSA codec
+ power supply enable or disable. This driver acts as interface
+ between codec and regulator framework.
+
+config WCD9XXX_CODEC_UTIL
+ tristate "WCD9XXX Codec Utils"
+ select MFD_CORE
+ help
+ WCD9XXX Util driver provides APIs for WCD drivers to reset,
+ suspend/resume, regmap bus callback functions and read/write
+ functions. This driver also hides the underlying bus related
+ functionalities.
+
config WCD9330_CODEC
tristate "WCD9330 Codec"
select SLIMBUS
select MFD_CORE
+ select WCD9XXX_CODEC_UTIL
+ select MSM_CDC_SUPPLY
select REGMAP_ALLOW_WRITE_DEBUGFS
help
Enables the WCD9xxx codec core driver. The core driver provides
@@ -1530,9 +1549,12 @@ config WCD9330_CODEC
config WCD9335_CODEC
tristate "WCD9335 Codec"
- depends on SLIMBUS
+ select SLIMBUS
select SOUNDWIRE_WCD_CTRL
select MFD_CORE
+ select WCD9XXX_CODEC_UTIL
+ select MSM_CDC_SUPPLY
+ select MSM_CDC_PINCTRL
select REGMAP_ALLOW_WRITE_DEBUGFS
help
Enables the WCD9xxx codec core driver. The core driver provides
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 26c118f77484..794e525a72c9 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -191,11 +191,12 @@ obj-$(CONFIG_MFD_DLN2) += dln2.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
obj-$(CONFIG_MSM_CDC_PINCTRL) += msm-cdc-pinctrl.o
+obj-$(CONFIG_MSM_CDC_SUPPLY) += msm-cdc-supply.o
+obj-$(CONFIG_WCD9XXX_CODEC_UTIL) += wcd9xxx-utils.o
obj-$(CONFIG_WCD9330_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
- wcd9xxx-core-resource.o wcd9330-regmap.o
+ wcd9330-regmap.o
obj-$(CONFIG_WCD9335_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
- wcd9xxx-core-resource.o wcd9335-regmap.o\
- wcd9335-tables.o wcd-gpio-ctrl.o
+ wcd9335-regmap.o wcd9335-tables.o
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
diff --git a/drivers/mfd/msm-cdc-supply.c b/drivers/mfd/msm-cdc-supply.c
new file mode 100644
index 000000000000..d553f7b3f492
--- /dev/null
+++ b/drivers/mfd/msm-cdc-supply.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/msm-cdc-supply.h>
+#include <linux/regulator/consumer.h>
+
+#define CODEC_DT_MAX_PROP_SIZE 40
+
+static int msm_cdc_dt_parse_vreg_info(struct device *dev,
+ struct cdc_regulator *cdc_vreg,
+ const char *name, bool is_ond)
+{
+ char prop_name[CODEC_DT_MAX_PROP_SIZE];
+ struct device_node *regulator_node = NULL;
+ const __be32 *prop;
+ int len, rc;
+ u32 prop_val;
+
+ /* Parse supply name */
+ snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply", name);
+
+ regulator_node = of_parse_phandle(dev->of_node, prop_name, 0);
+ if (!regulator_node) {
+ dev_err(dev, "%s: Looking up %s property in node %s failed",
+ __func__, prop_name, dev->of_node->full_name);
+ rc = -EINVAL;
+ goto done;
+ }
+ cdc_vreg->name = name;
+ cdc_vreg->ondemand = is_ond;
+
+ /* Parse supply - voltage */
+ snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-voltage", name);
+ prop = of_get_property(dev->of_node, prop_name, &len);
+ if (!prop || (len != (2 * sizeof(__be32)))) {
+ dev_err(dev, "%s: %s %s property\n", __func__,
+ prop ? "invalid format" : "no", prop_name);
+ rc = -EINVAL;
+ goto done;
+ } else {
+ cdc_vreg->min_uV = be32_to_cpup(&prop[0]);
+ cdc_vreg->max_uV = be32_to_cpup(&prop[1]);
+ }
+
+ /* Parse supply - current */
+ snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-current", name);
+ rc = of_property_read_u32(dev->of_node, prop_name, &prop_val);
+ if (rc) {
+ dev_err(dev, "%s: Looking up %s property in node %s failed",
+ __func__, prop_name, dev->of_node->full_name);
+ goto done;
+ }
+ cdc_vreg->optimum_uA = prop_val;
+
+ dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n",
+ __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV,
+ cdc_vreg->optimum_uA, cdc_vreg->ondemand);
+
+done:
+ return rc;
+}
+
+static int msm_cdc_parse_supplies(struct device *dev,
+ struct cdc_regulator *cdc_reg,
+ const char *sup_list, int sup_cnt,
+ bool is_ond)
+{
+ int idx, rc = 0;
+ const char *name = NULL;
+
+ for (idx = 0; idx < sup_cnt; idx++) {
+ rc = of_property_read_string_index(dev->of_node, sup_list, idx,
+ &name);
+ if (rc) {
+ dev_err(dev, "%s: read string %s[%d] error (%d)\n",
+ __func__, sup_list, idx, rc);
+ goto done;
+ }
+
+ dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n",
+ __func__, name, sup_list);
+
+ rc = msm_cdc_dt_parse_vreg_info(dev, &cdc_reg[idx], name,
+ is_ond);
+ if (rc) {
+ dev_err(dev, "%s: parse %s vreg info failed (%d)\n",
+ __func__, name, rc);
+ goto done;
+ }
+ }
+
+done:
+ return rc;
+}
+
+static int msm_cdc_check_supply_param(struct device *dev,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies)
+{
+ if (!dev) {
+ pr_err("%s: device is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!cdc_vreg || (num_supplies <= 0)) {
+ dev_err(dev, "%s: supply check failed: vreg: %pK, num_supplies: %d\n",
+ __func__, cdc_vreg, num_supplies);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * msm_cdc_disable_static_supplies:
+ * Disable codec static supplies
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply disable is failed
+ */
+int msm_cdc_disable_static_supplies(struct device *dev,
+ struct regulator_bulk_data *supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies)
+{
+ int rc, i;
+
+ if ((!dev) || (!supplies) || (!cdc_vreg)) {
+ pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+ /* input parameter validation */
+ rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < num_supplies; i++) {
+ if (cdc_vreg[i].ondemand)
+ continue;
+
+ rc = regulator_disable(supplies[i].consumer);
+ if (rc)
+ dev_err(dev, "%s: failed to disable supply %s, err:%d\n",
+ __func__, supplies[i].supply, rc);
+ else
+ dev_dbg(dev, "%s: disabled regulator %s\n",
+ __func__, supplies[i].supply);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_cdc_disable_static_supplies);
+
+/*
+ * msm_cdc_release_supplies:
+ * Release codec power supplies
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply disable is failed
+ */
+int msm_cdc_release_supplies(struct device *dev,
+ struct regulator_bulk_data *supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies)
+{
+ int rc = 0;
+ int i;
+
+ if ((!dev) || (!supplies) || (!cdc_vreg)) {
+ pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+ /* input parameter validation */
+ rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+ if (rc)
+ return rc;
+
+ msm_cdc_disable_static_supplies(dev, supplies, cdc_vreg,
+ num_supplies);
+
+ for (i = 0; i < num_supplies; i++) {
+ if (regulator_count_voltages(supplies[i].consumer) < 0)
+ continue;
+
+ regulator_set_voltage(supplies[i].consumer, 0,
+ cdc_vreg[i].max_uV);
+ regulator_set_load(supplies[i].consumer, 0);
+ }
+
+ regulator_bulk_free(num_supplies, supplies);
+ devm_kfree(dev, supplies);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_cdc_release_supplies);
+
+/*
+ * msm_cdc_enable_static_supplies:
+ * Enable codec static supplies
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply enable is failed
+ */
+int msm_cdc_enable_static_supplies(struct device *dev,
+ struct regulator_bulk_data *supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies)
+{
+ int rc, i;
+
+ if ((!dev) || (!supplies) || (!cdc_vreg)) {
+ pr_err("%s: either dev or supplies or cdc_vreg is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+ /* input parameter validation */
+ rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < num_supplies; i++) {
+ if (cdc_vreg[i].ondemand)
+ continue;
+
+ rc = regulator_enable(supplies[i].consumer);
+ if (rc) {
+ dev_err(dev, "%s: failed to enable supply %s, rc: %d\n",
+ __func__, supplies[i].supply, rc);
+ break;
+ }
+ }
+
+ while (rc && i--)
+ if (!cdc_vreg[i].ondemand)
+ regulator_disable(supplies[i].consumer);
+
+ return rc;
+}
+EXPORT_SYMBOL(msm_cdc_enable_static_supplies);
+
+/*
+ * msm_cdc_init_supplies:
+ * Initialize codec static supplies with regulator get
+ *
+ * @dev: pointer to codec device
+ * @supplies: pointer to regulator bulk data
+ * @cdc_vreg: pointer to platform regulator data
+ * @num_supplies: number of supplies
+ *
+ * Return error code if supply init is failed
+ */
+int msm_cdc_init_supplies(struct device *dev,
+ struct regulator_bulk_data **supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies)
+{
+ struct regulator_bulk_data *vsup;
+ int rc;
+ int i;
+
+ if (!dev || !cdc_vreg) {
+ pr_err("%s: device pointer or dce_vreg is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+ /* input parameter validation */
+ rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies);
+ if (rc)
+ return rc;
+
+ vsup = devm_kcalloc(dev, num_supplies,
+ sizeof(struct regulator_bulk_data),
+ GFP_KERNEL);
+ if (!vsup)
+ return -ENOMEM;
+
+ for (i = 0; i < num_supplies; i++) {
+ if (!cdc_vreg[i].name) {
+ dev_err(dev, "%s: supply name not defined\n",
+ __func__);
+ rc = -EINVAL;
+ goto err_supply;
+ }
+ vsup[i].supply = cdc_vreg[i].name;
+ }
+
+ rc = devm_regulator_bulk_get(dev, num_supplies, vsup);
+ if (rc) {
+ dev_err(dev, "%s: failed to get supplies (%d)\n",
+ __func__, rc);
+ goto err_supply;
+ }
+
+ /* Set voltage and current on regulators */
+ for (i = 0; i < num_supplies; i++) {
+ if (regulator_count_voltages(vsup[i].consumer) < 0)
+ continue;
+
+ rc = regulator_set_voltage(vsup[i].consumer,
+ cdc_vreg[i].min_uV,
+ cdc_vreg[i].max_uV);
+ if (rc) {
+ dev_err(dev, "%s: set regulator voltage failed for %s, err:%d\n",
+ __func__, vsup[i].supply, rc);
+ goto err_set_supply;
+ }
+ rc = regulator_set_load(vsup[i].consumer,
+ cdc_vreg[i].optimum_uA);
+ if (rc < 0) {
+ dev_err(dev, "%s: set regulator optimum mode failed for %s, err:%d\n",
+ __func__, vsup[i].supply, rc);
+ goto err_set_supply;
+ }
+ }
+
+ *supplies = vsup;
+
+ return 0;
+
+err_set_supply:
+ for (i = 0; i < num_supplies; i++)
+ devm_regulator_put(vsup[i].consumer);
+err_supply:
+ devm_kfree(dev, vsup);
+ return rc;
+}
+EXPORT_SYMBOL(msm_cdc_init_supplies);
+
+/*
+ * msm_cdc_get_power_supplies:
+ * Get codec power supplies from device tree.
+ * Allocate memory to hold regulator data for
+ * all power supplies.
+ *
+ * @dev: pointer to codec device
+ * @cdc_vreg: pointer to codec regulator
+ * @total_num_supplies: total number of supplies read from DT
+ *
+ * Return error code if supply disable is failed
+ */
+int msm_cdc_get_power_supplies(struct device *dev,
+ struct cdc_regulator **cdc_vreg,
+ int *total_num_supplies)
+{
+ const char *static_prop_name = "qcom,cdc-static-supplies";
+ const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+ const char *cp_prop_name = "qcom,cdc-cp-supplies";
+ int static_sup_cnt = 0;
+ int ond_sup_cnt = 0;
+ int cp_sup_cnt = 0;
+ int num_supplies = 0;
+ struct cdc_regulator *cdc_reg;
+ int rc;
+
+ if (!dev) {
+ pr_err("%s: device pointer is NULL\n", __func__);
+ return -EINVAL;
+ }
+ static_sup_cnt = of_property_count_strings(dev->of_node,
+ static_prop_name);
+ if (IS_ERR_VALUE(static_sup_cnt)) {
+ dev_err(dev, "%s: Failed to get static supplies(%d)\n",
+ __func__, static_sup_cnt);
+ rc = static_sup_cnt;
+ goto err_supply_cnt;
+ }
+ ond_sup_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
+ if (IS_ERR_VALUE(ond_sup_cnt))
+ ond_sup_cnt = 0;
+
+ cp_sup_cnt = of_property_count_strings(dev->of_node,
+ cp_prop_name);
+ if (IS_ERR_VALUE(cp_sup_cnt))
+ cp_sup_cnt = 0;
+
+ num_supplies = static_sup_cnt + ond_sup_cnt + cp_sup_cnt;
+ if (num_supplies <= 0) {
+ dev_err(dev, "%s: supply count is 0 or negative\n", __func__);
+ rc = -EINVAL;
+ goto err_supply_cnt;
+ }
+
+ cdc_reg = devm_kcalloc(dev, num_supplies,
+ sizeof(struct cdc_regulator),
+ GFP_KERNEL);
+ if (!cdc_reg) {
+ rc = -ENOMEM;
+ goto err_mem_alloc;
+ }
+
+ rc = msm_cdc_parse_supplies(dev, cdc_reg, static_prop_name,
+ static_sup_cnt, false);
+ if (rc) {
+ dev_err(dev, "%s: failed to parse static supplies(%d)\n",
+ __func__, rc);
+ goto err_sup;
+ }
+
+ rc = msm_cdc_parse_supplies(dev, &cdc_reg[static_sup_cnt],
+ ond_prop_name, ond_sup_cnt,
+ true);
+ if (rc) {
+ dev_err(dev, "%s: failed to parse demand supplies(%d)\n",
+ __func__, rc);
+ goto err_sup;
+ }
+
+ rc = msm_cdc_parse_supplies(dev,
+ &cdc_reg[static_sup_cnt + ond_sup_cnt],
+ cp_prop_name, cp_sup_cnt, true);
+ if (rc) {
+ dev_err(dev, "%s: failed to parse cp supplies(%d)\n",
+ __func__, rc);
+ goto err_sup;
+ }
+
+ *cdc_vreg = cdc_reg;
+ *total_num_supplies = num_supplies;
+
+ return 0;
+
+err_sup:
+ devm_kfree(dev, cdc_reg);
+err_supply_cnt:
+err_mem_alloc:
+ return rc;
+}
+EXPORT_SYMBOL(msm_cdc_get_power_supplies);
+
diff --git a/drivers/mfd/wcd-gpio-ctrl.c b/drivers/mfd/wcd-gpio-ctrl.c
deleted file mode 100644
index d5e6caa4d519..000000000000
--- a/drivers/mfd/wcd-gpio-ctrl.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* Copyright (c) 2016, The Linux Foundation. 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 and
- * only 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <linux/mfd/wcd9xxx/wcd-gpio-ctrl.h>
-
-struct wcd_gpio_pinctrl_info {
- struct pinctrl *pinctrl;
- struct pinctrl_state *pinctrl_active;
- struct pinctrl_state *pinctrl_sleep;
-};
-
-static struct wcd_gpio_pinctrl_info *wcd_gpio_get_gpiodata(
- struct device_node *np)
-{
- struct platform_device *pdev;
- struct wcd_gpio_pinctrl_info *gpio_data;
-
- if (!np) {
- pr_err("%s: device node is null\n", __func__);
- return NULL;
- }
-
- pdev = of_find_device_by_node(np);
- if (!pdev) {
- pr_err("%s: platform device not found!\n", __func__);
- return NULL;
- }
-
- gpio_data = dev_get_drvdata(&pdev->dev);
- if (!gpio_data)
- dev_err(&pdev->dev, "%s: cannot find cdc gpio info\n",
- __func__);
-
- return gpio_data;
-}
-
-/*
- * wcd_gpio_ctrl_select_sleep_state: select pinctrl sleep state
- * @np: pointer to struct device_node
- *
- * Returns error code for failure
- */
-int wcd_gpio_ctrl_select_sleep_state(struct device_node *np)
-{
- struct wcd_gpio_pinctrl_info *gpio_data;
-
- gpio_data = wcd_gpio_get_gpiodata(np);
- if (!gpio_data)
- return -EINVAL;
-
- if (!gpio_data->pinctrl_sleep) {
- pr_err("%s: pinctrl sleep state is null\n", __func__);
- return -EINVAL;
- }
-
- return pinctrl_select_state(gpio_data->pinctrl,
- gpio_data->pinctrl_sleep);
-}
-EXPORT_SYMBOL(wcd_gpio_ctrl_select_sleep_state);
-
-/*
- * wcd_gpio_ctrl_select_active_state: select pinctrl active state
- * @np: pointer to struct device_node
- *
- * Returns error code for failure
- */
-int wcd_gpio_ctrl_select_active_state(struct device_node *np)
-{
- struct wcd_gpio_pinctrl_info *gpio_data;
-
- gpio_data = wcd_gpio_get_gpiodata(np);
- if (!gpio_data)
- return -EINVAL;
-
- if (!gpio_data->pinctrl_active) {
- pr_err("%s: pinctrl active state is null\n", __func__);
- return -EINVAL;
- }
-
- return pinctrl_select_state(gpio_data->pinctrl,
- gpio_data->pinctrl_active);
-}
-EXPORT_SYMBOL(wcd_gpio_ctrl_select_active_state);
-
-static int wcd_gpio_ctrl_probe(struct platform_device *pdev)
-{
- int ret = 0;
- struct wcd_gpio_pinctrl_info *gpio_data;
-
- gpio_data = devm_kzalloc(&pdev->dev,
- sizeof(struct wcd_gpio_pinctrl_info),
- GFP_KERNEL);
- if (!gpio_data)
- return -ENOMEM;
-
- gpio_data->pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR_OR_NULL(gpio_data->pinctrl)) {
- dev_err(&pdev->dev, "%s: Cannot get cdc gpio pinctrl:%ld\n",
- __func__, PTR_ERR(gpio_data->pinctrl));
- ret = PTR_ERR(gpio_data->pinctrl);
- goto err_pctrl_get;
- }
-
- gpio_data->pinctrl_active = pinctrl_lookup_state(
- gpio_data->pinctrl, "aud_active");
- if (IS_ERR_OR_NULL(gpio_data->pinctrl_active)) {
- dev_err(&pdev->dev, "%s: Cannot get aud_active pinctrl state:%ld\n",
- __func__, PTR_ERR(gpio_data->pinctrl_active));
- ret = PTR_ERR(gpio_data->pinctrl_active);
- goto err_lookup_state;
- }
-
- gpio_data->pinctrl_sleep = pinctrl_lookup_state(
- gpio_data->pinctrl, "aud_sleep");
- if (IS_ERR_OR_NULL(gpio_data->pinctrl_sleep)) {
- dev_err(&pdev->dev, "%s: Cannot get aud_sleep pinctrl state:%ld\n",
- __func__, PTR_ERR(gpio_data->pinctrl_sleep));
- ret = PTR_ERR(gpio_data->pinctrl_sleep);
- goto err_lookup_state;
- }
-
- /* Set pinctrl state to aud_sleep by default */
- ret = pinctrl_select_state(gpio_data->pinctrl,
- gpio_data->pinctrl_sleep);
- if (ret)
- dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n",
- __func__, ret);
-
- dev_set_drvdata(&pdev->dev, gpio_data);
- return 0;
-
-err_lookup_state:
- devm_pinctrl_put(gpio_data->pinctrl);
-err_pctrl_get:
- devm_kfree(&pdev->dev, gpio_data);
- return ret;
-}
-
-static int wcd_gpio_ctrl_remove(struct platform_device *pdev)
-{
- struct wcd_gpio_pinctrl_info *gpio_data;
-
- gpio_data = dev_get_drvdata(&pdev->dev);
-
- if (gpio_data && gpio_data->pinctrl)
- devm_pinctrl_put(gpio_data->pinctrl);
-
- devm_kfree(&pdev->dev, gpio_data);
-
- return 0;
-}
-
-static const struct of_device_id wcd_gpio_ctrl_match[] = {
- {.compatible = "qcom,wcd-gpio-ctrl"},
- {}
-};
-
-static struct platform_driver wcd_gpio_ctrl_driver = {
- .driver = {
- .name = "wcd-gpio-ctrl",
- .owner = THIS_MODULE,
- .of_match_table = wcd_gpio_ctrl_match,
- },
- .probe = wcd_gpio_ctrl_probe,
- .remove = wcd_gpio_ctrl_remove,
-};
-module_platform_driver(wcd_gpio_ctrl_driver);
-
-MODULE_DESCRIPTION("WCD GPIO Control module platform driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/wcd9330-regmap.c b/drivers/mfd/wcd9330-regmap.c
index 5ae2de3fafbc..e7f2ae13a4ae 100644
--- a/drivers/mfd/wcd9330-regmap.c
+++ b/drivers/mfd/wcd9330-regmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. 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 and
@@ -12,7 +12,6 @@
*/
#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
#include <linux/mfd/wcd9xxx/wcd9330_registers.h>
#include <linux/regmap.h>
#include <linux/device.h>
diff --git a/drivers/mfd/wcd9335-regmap.c b/drivers/mfd/wcd9335-regmap.c
index e2a5028cb8d2..082a52791717 100644
--- a/drivers/mfd/wcd9335-regmap.c
+++ b/drivers/mfd/wcd9335-regmap.c
@@ -12,7 +12,6 @@
*/
#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
#include <linux/mfd/wcd9335/registers.h>
#include <linux/regmap.h>
#include <linux/device.h>
diff --git a/drivers/mfd/wcd9xxx-core-resource.c b/drivers/mfd/wcd9xxx-core-resource.c
deleted file mode 100644
index 1d0f894f9cb4..000000000000
--- a/drivers/mfd/wcd9xxx-core-resource.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. 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 and
- * only 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
-
-
-static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
-
-int wcd9xxx_core_irq_init(
- struct wcd9xxx_core_resource *wcd9xxx_core_res)
-{
- int ret = 0;
-
- if (wcd9xxx_core_res->irq != 1) {
- ret = wcd9xxx_irq_init(wcd9xxx_core_res);
- if (ret)
- pr_err("IRQ initialization failed\n");
- }
-
- return ret;
-}
-EXPORT_SYMBOL(wcd9xxx_core_irq_init);
-
-int wcd9xxx_initialize_irq(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- unsigned int irq,
- unsigned int irq_base)
-{
- wcd9xxx_core_res->irq = irq;
- wcd9xxx_core_res->irq_base = irq_base;
-
- return 0;
-}
-EXPORT_SYMBOL(wcd9xxx_initialize_irq);
-
-int wcd9xxx_core_res_init(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- int num_irqs, int num_irq_regs,
- int (*codec_read)(struct wcd9xxx_core_resource*, unsigned short),
- int (*codec_write)(struct wcd9xxx_core_resource*, unsigned short, u8),
- int (*codec_bulk_read) (struct wcd9xxx_core_resource*, unsigned short,
- int, u8*),
- int (*codec_bulk_write) (struct wcd9xxx_core_resource*, unsigned short,
- int, u8*))
-{
- mutex_init(&wcd9xxx_core_res->pm_lock);
- wcd9xxx_core_res->wlock_holders = 0;
- wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
- init_waitqueue_head(&wcd9xxx_core_res->pm_wq);
- pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req,
- PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
- wcd9xxx_core_res->codec_reg_read = codec_read;
- wcd9xxx_core_res->codec_reg_write = codec_write;
- wcd9xxx_core_res->codec_bulk_read = codec_bulk_read;
- wcd9xxx_core_res->codec_bulk_write = codec_bulk_write;
- wcd9xxx_core_res->num_irqs = num_irqs;
- wcd9xxx_core_res->num_irq_regs = num_irq_regs;
-
- pr_info("%s: num_irqs = %d, num_irq_regs = %d\n",
- __func__, wcd9xxx_core_res->num_irqs,
- wcd9xxx_core_res->num_irq_regs);
-
- return 0;
-}
-EXPORT_SYMBOL(wcd9xxx_core_res_init);
-
-void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res)
-{
- pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req);
- mutex_destroy(&wcd9xxx_core_res->pm_lock);
- wcd9xxx_core_res->codec_reg_read = NULL;
- wcd9xxx_core_res->codec_reg_write = NULL;
- wcd9xxx_core_res->codec_bulk_read = NULL;
-}
-EXPORT_SYMBOL(wcd9xxx_core_res_deinit);
-
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- enum wcd9xxx_pm_state o,
- enum wcd9xxx_pm_state n)
-{
- enum wcd9xxx_pm_state old;
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- old = wcd9xxx_core_res->pm_state;
- if (old == o)
- wcd9xxx_core_res->pm_state = n;
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
- return old;
-}
-EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg);
-
-int wcd9xxx_core_res_suspend(
- struct wcd9xxx_core_resource *wcd9xxx_core_res,
- pm_message_t pmesg)
-{
- int ret = 0;
-
- pr_debug("%s: enter\n", __func__);
- /*
- * pm_qos_update_request() can be called after this suspend chain call
- * started. thus suspend can be called while lock is being held
- */
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) {
- pr_debug("%s: suspending system, state %d, wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP;
- } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) {
- /*
- * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
- * then set to WCD9XXX_PM_ASLEEP
- */
- pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
- if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq,
- wcd9xxx_pm_cmpxchg(wcd9xxx_core_res,
- WCD9XXX_PM_SLEEPABLE,
- WCD9XXX_PM_ASLEEP) ==
- WCD9XXX_PM_SLEEPABLE,
- HZ))) {
- pr_debug("%s: suspend failed state %d, wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- ret = -EBUSY;
- } else {
- pr_debug("%s: done, state %d, wlock %d\n", __func__,
- wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- }
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
- pr_warn("%s: system is already suspended, state %d, wlock %dn",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- }
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(wcd9xxx_core_res_suspend);
-
-int wcd9xxx_core_res_resume(
- struct wcd9xxx_core_resource *wcd9xxx_core_res)
-{
- int ret = 0;
-
- pr_debug("%s: enter\n", __func__);
- mutex_lock(&wcd9xxx_core_res->pm_lock);
- if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
- pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
- wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
- } else {
- pr_warn("%s: system is already awake, state %d wlock %d\n",
- __func__, wcd9xxx_core_res->pm_state,
- wcd9xxx_core_res->wlock_holders);
- }
- mutex_unlock(&wcd9xxx_core_res->pm_lock);
- wake_up_all(&wcd9xxx_core_res->pm_wq);
-
- return ret;
-}
-EXPORT_SYMBOL(wcd9xxx_core_res_resume);
-
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
-{
- return wcd9xxx_intf;
-}
-EXPORT_SYMBOL(wcd9xxx_get_intf_type);
-
-void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status)
-{
- wcd9xxx_intf = intf_status;
-}
-EXPORT_SYMBOL(wcd9xxx_set_intf_type);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index ddd92aa57dd5..555fac10377f 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -12,24 +12,21 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/of_irq.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/ratelimit.h>
#include <linux/mfd/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
#include <linux/mfd/wcd9xxx/pdata.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
-#include <linux/mfd/wcd9xxx/wcd-gpio-ctrl.h>
-#include <linux/mfd/wcd9335/registers.h>
-
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-utils.h>
+#include <linux/mfd/msm-cdc-supply.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/debugfs.h>
-#include <linux/regulator/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <sound/soc.h>
@@ -40,7 +37,6 @@
#define SLIMBUS_PRESENT_TIMEOUT 100
#define MAX_WCD9XXX_DEVICE 4
-#define CODEC_DT_MAX_PROP_SIZE 40
#define WCD9XXX_I2C_GSBI_SLAVE_ID "3-000d"
#define WCD9XXX_I2C_TOP_SLAVE_ADDR 0x0d
#define WCD9XXX_ANALOG_I2C_SLAVE_ADDR 0x77
@@ -51,24 +47,18 @@
#define WCD9XXX_I2C_DIGITAL_1 2
#define WCD9XXX_I2C_DIGITAL_2 3
-#define ONDEMAND_REGULATOR true
-#define STATIC_REGULATOR (!ONDEMAND_REGULATOR)
-/* Page Register Address that APP Proc uses to
- * access WCD9335 Codec registers is identified
- * as 0x00
- */
-#define PAGE_REG_ADDR 0x00
-
-/* Number of return values needs to be checked for each
+/*
+ * Number of return values needs to be checked for each
* registration of Slimbus of I2C bus for each codec
*/
-#define NUM_WCD9XXX_REG_RET 11
+#define NUM_WCD9XXX_REG_RET 4
#define SLIM_USR_MC_REPEAT_CHANGE_VALUE 0x0
#define SLIM_REPEAT_WRITE_MAX_SLICE 16
#define REG_BYTES 2
#define VAL_BYTES 1
#define WCD9XXX_PAGE_NUM(reg) (((reg) >> 8) & 0xff)
+#define WCD9XXX_PAGE_SIZE 256
struct wcd9xxx_i2c {
struct i2c_client *client;
@@ -77,14 +67,6 @@ struct wcd9xxx_i2c {
int mod_id;
};
-struct pinctrl_info {
- struct pinctrl *pinctrl;
- struct pinctrl_state *extncodec_sus;
- struct pinctrl_state *extncodec_act;
-};
-
-static struct pinctrl_info pinctrl_info;
-
static struct regmap_config wcd9xxx_base_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
@@ -98,6 +80,9 @@ static struct regmap_config wcd9xxx_i2c_base_regmap_config = {
.use_single_rw = true,
};
+static u8 wcd9xxx_pgd_la;
+static u8 wcd9xxx_inf_la;
+
static const int wcd9xxx_cdc_types[] = {
[WCD9XXX] = WCD9XXX,
[WCD9330] = WCD9330,
@@ -105,10 +90,6 @@ static const int wcd9xxx_cdc_types[] = {
};
static const struct of_device_id wcd9xxx_of_match[] = {
- { .compatible = "qcom,tomtom-slim-pgd",
- .data = (void *)&wcd9xxx_cdc_types[WCD9330]},
- { .compatible = "qcom,tasha-slim-pgd",
- .data = (void *)&wcd9xxx_cdc_types[WCD9335]},
{ .compatible = "qcom,tasha-i2c-pgd",
.data = (void *)&wcd9xxx_cdc_types[WCD9335]},
{ .compatible = "qcom,wcd9xxx-i2c",
@@ -117,255 +98,17 @@ static const struct of_device_id wcd9xxx_of_match[] = {
};
MODULE_DEVICE_TABLE(of, wcd9xxx_of_match);
-static void wcd9xxx_set_codec_specific_param(struct wcd9xxx *wcd9xxx);
-static struct regmap *devm_regmap_init_i2c_bus(struct i2c_client *i2c,
- const struct regmap_config *config);
-
-static int extcodec_get_pinctrl(struct device *dev)
-{
- struct pinctrl *pinctrl;
-
- pinctrl = devm_pinctrl_get(dev);
- if (IS_ERR(pinctrl)) {
- pr_err("%s: Unable to get pinctrl handle\n", __func__);
- return -EINVAL;
- }
- pinctrl_info.pinctrl = pinctrl;
- /* get all the states handles from Device Tree */
- pinctrl_info.extncodec_sus = pinctrl_lookup_state(pinctrl, "idle");
- if (IS_ERR(pinctrl_info.extncodec_sus)) {
- pr_err("%s: Unable to get pinctrl disable state handle, err: %ld\n",
- __func__, PTR_ERR(pinctrl_info.extncodec_sus));
- return -EINVAL;
- }
- pinctrl_info.extncodec_act = pinctrl_lookup_state(pinctrl, "default");
- if (IS_ERR(pinctrl_info.extncodec_act)) {
- pr_err("%s: Unable to get pinctrl disable state handle, err: %ld\n",
- __func__, PTR_ERR(pinctrl_info.extncodec_act));
- return -EINVAL;
- }
- return 0;
-}
-
-static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
- struct wcd9xxx_regulator *vreg,
- const char *vreg_name, bool ondemand);
-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);
-
static int wcd9xxx_slim_device_up(struct slim_device *sldev);
static int wcd9xxx_slim_device_down(struct slim_device *sldev);
-static int wcd9xxx_enable_static_supplies(struct wcd9xxx *wcd9xxx,
- struct wcd9xxx_pdata *pdata);
-static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx,
- struct wcd9xxx_pdata *pdata);
struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int bytes, void *dest, bool interface_reg)
-{
- int i, ret;
-
- if (bytes <= 0) {
- dev_err(wcd9xxx->dev, "Invalid byte read length %d\n", bytes);
- return -EINVAL;
- }
-
- ret = wcd9xxx->read_dev(wcd9xxx, reg, bytes, dest, interface_reg);
- if (ret < 0) {
- dev_err(wcd9xxx->dev, "Codec read failed\n");
- return ret;
- } else {
- for (i = 0; i < bytes; i++)
- dev_dbg(wcd9xxx->dev, "Read 0x%02x from 0x%x\n",
- ((u8 *)dest)[i], reg + i);
- }
-
- return 0;
-}
-
-/* Called under io_lock acquisition */
-static int wcd9xxx_page_write(struct wcd9xxx *wcd9xxx, unsigned short *reg)
-{
- int ret = 0;
- unsigned short c_reg, reg_addr;
- u8 pg_num, prev_pg_num;
-
- if (wcd9xxx->type != WCD9335)
- return ret;
-
- c_reg = *reg;
- pg_num = c_reg >> 8;
- reg_addr = c_reg & 0xff;
- if (wcd9xxx->prev_pg_valid) {
- prev_pg_num = wcd9xxx->prev_pg;
- if (prev_pg_num != pg_num) {
- ret = wcd9xxx->write_dev(
- wcd9xxx, PAGE_REG_ADDR, 1,
- (void *) &pg_num, false);
- if (ret < 0)
- pr_err("page write error, pg_num: 0x%x\n",
- pg_num);
- else {
- wcd9xxx->prev_pg = pg_num;
- dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n",
- __func__, pg_num);
- }
- }
- } else {
- ret = wcd9xxx->write_dev(
- wcd9xxx, PAGE_REG_ADDR, 1, (void *) &pg_num,
- false);
- if (ret < 0)
- pr_err("page write error, pg_num: 0x%x\n", pg_num);
- else {
- wcd9xxx->prev_pg = pg_num;
- wcd9xxx->prev_pg_valid = true;
- dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n",
- __func__, pg_num);
- }
- }
- *reg = reg_addr;
- return ret;
-}
-
-static bool is_wcd9xxx_reg_power_down(struct wcd9xxx *wcd9xxx, u16 rreg)
-{
- bool ret = false;
- int i;
- struct wcd9xxx_power_region *wcd9xxx_pwr;
-
- if (!wcd9xxx)
- return ret;
-
- for (i = 0; i < WCD9XXX_MAX_PWR_REGIONS; i++) {
- wcd9xxx_pwr = wcd9xxx->wcd9xxx_pwr[i];
- if (!wcd9xxx_pwr)
- continue;
- if (((wcd9xxx_pwr->pwr_collapse_reg_min == 0) &&
- (wcd9xxx_pwr->pwr_collapse_reg_max == 0)) ||
- (wcd9xxx_pwr->power_state ==
- WCD_REGION_POWER_COLLAPSE_REMOVE))
- ret = false;
- else if (((wcd9xxx_pwr->power_state ==
- WCD_REGION_POWER_DOWN) ||
- (wcd9xxx_pwr->power_state ==
- WCD_REGION_POWER_COLLAPSE_BEGIN)) &&
- (rreg >= wcd9xxx_pwr->pwr_collapse_reg_min) &&
- (rreg <= wcd9xxx_pwr->pwr_collapse_reg_max))
- ret = true;
- }
- return ret;
-}
-
-static int regmap_bus_read(void *context, const void *reg, size_t reg_size,
- void *val, size_t val_size)
-{
- struct device *dev = context;
- struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
- unsigned short c_reg, rreg;
- int ret, i;
-
- if (!wcd9xxx) {
- dev_err(dev, "%s: wcd9xxx is NULL\n", __func__);
- return -EINVAL;
- }
- if (!reg || !val) {
- dev_err(dev, "%s: reg or val is NULL\n", __func__);
- return -EINVAL;
- }
-
- if (reg_size != REG_BYTES) {
- dev_err(dev, "%s: register size %zd bytes, not supported\n",
- __func__, reg_size);
- return -EINVAL;
- }
-
- mutex_lock(&wcd9xxx->io_lock);
- c_reg = *(u16 *)reg;
- rreg = c_reg;
-
- if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) {
- ret = 0;
- for (i = 0; i < val_size; i++)
- ((u8 *)val)[i] = 0;
- goto err;
- }
- ret = wcd9xxx_page_write(wcd9xxx, &c_reg);
- if (ret)
- goto err;
- ret = wcd9xxx->read_dev(wcd9xxx, c_reg, val_size, val, false);
- if (ret < 0)
- dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n",
- __func__, ret, rreg, val_size);
- else {
- for (i = 0; i < val_size; i++)
- dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n",
- __func__, ((u8 *)val)[i], rreg + i);
- }
-err:
- mutex_unlock(&wcd9xxx->io_lock);
-
- return ret;
-}
-
-static int __wcd9xxx_reg_read(
- struct wcd9xxx *wcd9xxx,
- unsigned short reg)
-{
- unsigned int val = 0;
- int ret;
-
- if (wcd9xxx->using_regmap) {
- ret = regmap_read(wcd9xxx->regmap, reg, &val);
- } else {
- mutex_lock(&wcd9xxx->io_lock);
- ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, false);
- mutex_unlock(&wcd9xxx->io_lock);
- }
-
- if (ret < 0)
- return ret;
- else
- return val;
-}
-
-int wcd9xxx_reg_read(
- struct wcd9xxx_core_resource *core_res,
- unsigned short reg)
-{
- struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
- return __wcd9xxx_reg_read(wcd9xxx, reg);
-
-}
-EXPORT_SYMBOL(wcd9xxx_reg_read);
-
-static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int bytes, void *src, bool interface_reg)
-{
- int i;
-
- if (bytes <= 0) {
- pr_err("%s: Error, invalid write length\n", __func__);
- return -EINVAL;
- }
-
- for (i = 0; i < bytes; i++)
- dev_dbg(wcd9xxx->dev, "Write %02x to 0x%x\n", ((u8 *)src)[i],
- reg + i);
-
- return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
-}
-
-static int regmap_slim_multi_reg_write(void *context,
- const void *data, size_t count)
+static int wcd9xxx_slim_multi_reg_write(struct wcd9xxx *wcd9xxx,
+ const void *data, size_t count)
{
- struct device *dev = context;
- struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
unsigned int reg;
- u8 val[WCD9335_PAGE_SIZE];
+ struct device *dev;
+ u8 val[WCD9XXX_PAGE_SIZE];
int ret = 0;
int i = 0;
int n = 0;
@@ -374,10 +117,7 @@ static int regmap_slim_multi_reg_write(void *context,
struct wcd9xxx_reg_val *bulk_reg;
u8 *buf;
- if (!wcd9xxx) {
- dev_err(dev, "%s: wcd9xxx is NULL\n", __func__);
- return -EINVAL;
- }
+ dev = wcd9xxx->dev;
if (!data) {
dev_err(dev, "%s: data is NULL\n", __func__);
return -EINVAL;
@@ -418,138 +158,29 @@ static int regmap_slim_multi_reg_write(void *context,
return ret;
}
-static int regmap_bus_gather_write(void *context,
- const void *reg, size_t reg_size,
- const void *val, size_t val_size)
-{
- struct device *dev = context;
- struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
- unsigned short c_reg, rreg;
- int ret, i;
-
- if (!wcd9xxx) {
- dev_err(dev, "%s: wcd9xxx is NULL\n", __func__);
- return -EINVAL;
- }
- if (!reg || !val) {
- dev_err(dev, "%s: reg or val is NULL\n", __func__);
- return -EINVAL;
- }
- if (reg_size != REG_BYTES) {
- dev_err(dev, "%s: register size %zd bytes, not supported\n",
- __func__, reg_size);
- return -EINVAL;
- }
- mutex_lock(&wcd9xxx->io_lock);
- c_reg = *(u16 *)reg;
- rreg = c_reg;
-
- if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) {
- ret = 0;
- goto err;
- }
- ret = wcd9xxx_page_write(wcd9xxx, &c_reg);
- if (ret)
- goto err;
-
- for (i = 0; i < val_size; i++)
- dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i],
- rreg + i);
-
- ret = wcd9xxx->write_dev(wcd9xxx, c_reg, val_size, (void *) val,
- false);
- if (ret < 0)
- dev_err(dev, "%s: Codec write failed (%d), reg:0x%x, size:%zd\n",
- __func__, ret, rreg, val_size);
-
-err:
- mutex_unlock(&wcd9xxx->io_lock);
- return ret;
-}
-
-static int regmap_bus_write(void *context, const void *data, size_t count)
-{
- WARN_ON(count < REG_BYTES);
-
- if (count > (REG_BYTES + VAL_BYTES))
- return regmap_slim_multi_reg_write(context, data, count);
- else
- return regmap_bus_gather_write(context, data, REG_BYTES,
- data + REG_BYTES,
- count - REG_BYTES);
-}
-
-static int __wcd9xxx_reg_write(
- struct wcd9xxx *wcd9xxx,
- unsigned short reg, u8 val)
-{
- int ret;
-
- if (wcd9xxx->using_regmap)
- ret = regmap_write(wcd9xxx->regmap, reg, val);
- else {
- mutex_lock(&wcd9xxx->io_lock);
- ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, false);
- mutex_unlock(&wcd9xxx->io_lock);
- }
-
- return ret;
-}
-
-static int __wcd9xxx_reg_update_bits(struct wcd9xxx *wcd9xxx,
- unsigned short reg, u8 mask, u8 val)
-{
- int ret;
- u8 orig, tmp;
-
- if (wcd9xxx->using_regmap)
- ret = regmap_update_bits(wcd9xxx->regmap, reg, mask, val);
- else {
- mutex_lock(&wcd9xxx->io_lock);
- ret = wcd9xxx_read(wcd9xxx, reg, 1, &orig, false);
- if (ret < 0) {
- dev_err(wcd9xxx->dev, "%s: Codec read 0x%x failed\n",
- __func__, reg);
- goto err;
- }
- tmp = orig & ~mask;
- tmp |= val & mask;
- if (tmp != orig)
- ret = wcd9xxx_write(wcd9xxx, reg, 1, &tmp, false);
-err:
- mutex_unlock(&wcd9xxx->io_lock);
- }
- return ret;
-}
-
-int wcd9xxx_reg_update_bits(
- struct wcd9xxx_core_resource *core_res,
- unsigned short reg, u8 mask, u8 val)
-{
- struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
- return __wcd9xxx_reg_update_bits(wcd9xxx, reg, mask, val);
-}
-EXPORT_SYMBOL(wcd9xxx_reg_update_bits);
-
-int wcd9xxx_reg_write(
- struct wcd9xxx_core_resource *core_res,
- unsigned short reg, u8 val)
-{
- struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
- return __wcd9xxx_reg_write(wcd9xxx, reg, val);
-}
-EXPORT_SYMBOL(wcd9xxx_reg_write);
-
-static u8 wcd9xxx_pgd_la;
-static u8 wcd9xxx_inf_la;
-
+/*
+ * wcd9xxx_interface_reg_read: Read slim interface registers
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ * @reg: register adderss
+ *
+ * Returns register value in success and negative error code in case of failure
+ */
int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
{
u8 val;
int ret;
mutex_lock(&wcd9xxx->io_lock);
- ret = wcd9xxx_read(wcd9xxx, reg, 1, &val, true);
+ ret = wcd9xxx->read_dev(wcd9xxx, reg, 1, (void *)&val,
+ true);
+ if (ret < 0)
+ dev_err(wcd9xxx->dev, "%s: Codec read 0x%x failed\n",
+ __func__, reg);
+ else
+ dev_dbg(wcd9xxx->dev, "%s: Read 0x%02x from 0x%x\n",
+ __func__, val, reg);
+
mutex_unlock(&wcd9xxx->io_lock);
if (ret < 0)
@@ -559,175 +190,101 @@ int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
}
EXPORT_SYMBOL(wcd9xxx_interface_reg_read);
+/*
+ * wcd9xxx_interface_reg_write: Write slim interface registers
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ * @reg: register adderss
+ * @val: value of the register to be written
+ *
+ * Returns 0 for success and negative error code in case of failure
+ */
int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
u8 val)
{
int ret;
mutex_lock(&wcd9xxx->io_lock);
- ret = wcd9xxx_write(wcd9xxx, reg, 1, &val, true);
+ ret = wcd9xxx->write_dev(wcd9xxx, reg, 1, (void *)&val, true);
+ dev_dbg(wcd9xxx->dev, "%s: Write %02x to 0x%x ret(%d)\n",
+ __func__, val, reg, ret);
mutex_unlock(&wcd9xxx->io_lock);
return ret;
}
EXPORT_SYMBOL(wcd9xxx_interface_reg_write);
-static int __wcd9xxx_bulk_read(
- struct wcd9xxx *wcd9xxx,
- unsigned short reg,
- int count, u8 *buf)
-{
- int ret;
-
- if (wcd9xxx->using_regmap) {
- ret = regmap_bulk_read(wcd9xxx->regmap, reg, buf, count);
- } else {
- mutex_lock(&wcd9xxx->io_lock);
- ret = wcd9xxx_read(wcd9xxx, reg, count, buf, false);
- mutex_unlock(&wcd9xxx->io_lock);
- }
-
- return ret;
-}
-
-int wcd9xxx_bulk_read(
- struct wcd9xxx_core_resource *core_res,
- unsigned short reg,
- int count, u8 *buf)
-{
- struct wcd9xxx *wcd9xxx =
- (struct wcd9xxx *) core_res->parent;
- return __wcd9xxx_bulk_read(wcd9xxx, reg, count, buf);
-}
-EXPORT_SYMBOL(wcd9xxx_bulk_read);
-
-static int __wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int count, u8 *buf)
+static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *dest, bool interface)
{
int ret;
+ struct slim_ele_access msg;
+ int slim_read_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
- if (wcd9xxx->using_regmap) {
- ret = regmap_bulk_write(wcd9xxx->regmap, reg, buf, count);
- } else {
- mutex_lock(&wcd9xxx->io_lock);
- ret = wcd9xxx_write(wcd9xxx, reg, count, buf, false);
- mutex_unlock(&wcd9xxx->io_lock);
- }
-
- return ret;
-}
-
-int wcd9xxx_bulk_write(
- struct wcd9xxx_core_resource *core_res,
- unsigned short reg, int count, u8 *buf)
-{
- struct wcd9xxx *wcd9xxx =
- (struct wcd9xxx *) core_res->parent;
- return __wcd9xxx_bulk_write(wcd9xxx, reg, count, buf);
-}
-EXPORT_SYMBOL(wcd9xxx_bulk_write);
-
-/*
- * wcd9xxx_get_current_power_state: Get power state of the region
- * @wcd9xxx: handle to wcd core
- * @region: region index
- *
- * Returns current power state of the region or error code for failure
- */
-int wcd9xxx_get_current_power_state(struct wcd9xxx *wcd9xxx,
- enum wcd_power_regions region)
-{
- int state;
+ msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
+ msg.num_bytes = bytes;
+ msg.comp = NULL;
- if (!wcd9xxx) {
- pr_err("%s: wcd9xxx is NULL\n", __func__);
- return -EINVAL;
+ if (!wcd9xxx->dev_up) {
+ dev_dbg_ratelimited(
+ wcd9xxx->dev, "%s: No read allowed. dev_up = %d\n",
+ __func__, wcd9xxx->dev_up);
+ return 0;
}
- if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) {
- dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n",
- __func__, region);
- return -EINVAL;
- }
- if (!wcd9xxx->wcd9xxx_pwr[region]) {
- dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n",
- __func__, region);
- return -EINVAL;
+ while (1) {
+ mutex_lock(&wcd9xxx->xfer_lock);
+ ret = slim_request_val_element(interface ?
+ wcd9xxx->slim_slave : wcd9xxx->slim,
+ &msg, dest, bytes);
+ mutex_unlock(&wcd9xxx->xfer_lock);
+ if (likely(ret == 0) || (--slim_read_tries == 0))
+ break;
+ usleep_range(5000, 5100);
}
- mutex_lock(&wcd9xxx->io_lock);
- state = wcd9xxx->wcd9xxx_pwr[region]->power_state;
- mutex_unlock(&wcd9xxx->io_lock);
+ if (ret)
+ dev_err(wcd9xxx->dev, "%s: Error, Codec read failed (%d)\n",
+ __func__, ret);
- return state;
+ return ret;
}
-EXPORT_SYMBOL(wcd9xxx_get_current_power_state);
/*
- * wcd9xxx_set_power_state: set power state for the region
- * @wcd9xxx: handle to wcd core
- * @state: power state to be set
- * @region: region index
- *
- * Returns error code in case of failure or 0 for success
+ * Interface specifies whether the write is to the interface or general
+ * registers.
*/
-int wcd9xxx_set_power_state(struct wcd9xxx *wcd9xxx,
- enum codec_power_states state,
- enum wcd_power_regions region)
-{
- if (!wcd9xxx) {
- pr_err("%s: wcd9xxx is NULL\n", __func__);
- return -EINVAL;
- }
-
- if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) {
- dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n",
- __func__, region);
- return -EINVAL;
- }
- if (!wcd9xxx->wcd9xxx_pwr[region]) {
- dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n",
- __func__, region);
- return -EINVAL;
- }
- mutex_lock(&wcd9xxx->io_lock);
- wcd9xxx->wcd9xxx_pwr[region]->power_state = state;
- mutex_unlock(&wcd9xxx->io_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(wcd9xxx_set_power_state);
-
-static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int bytes, void *dest, bool interface)
+static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx,
+ unsigned short reg, int bytes, void *src, bool interface)
{
int ret;
struct slim_ele_access msg;
- int slim_read_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+ int slim_write_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
+
msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
msg.num_bytes = bytes;
msg.comp = NULL;
if (!wcd9xxx->dev_up) {
dev_dbg_ratelimited(
- wcd9xxx->dev, "%s: No read allowed. dev_up = %d\n",
+ wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n",
__func__, wcd9xxx->dev_up);
return 0;
}
while (1) {
mutex_lock(&wcd9xxx->xfer_lock);
- ret = slim_request_val_element(interface ?
- wcd9xxx->slim_slave : wcd9xxx->slim,
- &msg, dest, bytes);
+ ret = slim_change_val_element(interface ?
+ wcd9xxx->slim_slave : wcd9xxx->slim,
+ &msg, src, bytes);
mutex_unlock(&wcd9xxx->xfer_lock);
- if (likely(ret == 0) || (--slim_read_tries == 0))
+ if (likely(ret == 0) || (--slim_write_tries == 0))
break;
usleep_range(5000, 5100);
}
if (ret)
- pr_err("%s: Error, Codec read failed (%d)\n", __func__, ret);
+ pr_err("%s: Error, Codec write failed (%d)\n", __func__, ret);
return ret;
}
@@ -753,27 +310,44 @@ static int wcd9xxx_slim_get_allowed_slice(struct wcd9xxx *wcd9xxx,
return allowed_sz;
}
-static int __wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx,
- unsigned short reg,
- int bytes, void *src)
+/*
+ * wcd9xxx_slim_write_repeat: Write the same register with multiple values
+ * @wcd9xxx: handle to wcd core
+ * @reg: register to be written
+ * @bytes: number of bytes to be written to reg
+ * @src: buffer with data content to be written to reg
+ * This API will write reg with bytes from src in a single slimbus
+ * transaction. All values from 1 to 16 are supported by this API.
+ */
+int wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx, unsigned short reg,
+ int bytes, void *src)
{
int ret = 0, bytes_to_write = bytes, bytes_allowed;
struct slim_ele_access slim_msg;
+ mutex_lock(&wcd9xxx->io_lock);
+ if (wcd9xxx->type == WCD9335) {
+ ret = wcd9xxx_page_write(wcd9xxx, &reg);
+ if (ret)
+ goto done;
+ }
+
slim_msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
slim_msg.comp = NULL;
if (unlikely(bytes > SLIM_REPEAT_WRITE_MAX_SLICE)) {
dev_err(wcd9xxx->dev, "%s: size %d not supported\n",
__func__, bytes);
- return -EINVAL;
+ ret = -EINVAL;
+ goto done;
}
if (!wcd9xxx->dev_up) {
dev_dbg_ratelimited(
wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n",
__func__, wcd9xxx->dev_up);
- return 0;
+ ret = 0;
+ goto done;
}
while (bytes_to_write > 0) {
@@ -796,41 +370,11 @@ static int __wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx,
bytes_to_write = bytes_to_write - bytes_allowed;
src = ((u8 *)src) + bytes_allowed;
- };
-
- return ret;
-}
-
-/*
- * wcd9xxx_slim_write_repeat: Write the same register with multiple values
- * @wcd9xxx: handle to wcd core
- * @reg: register to be written
- * @bytes: number of bytes to be written to reg
- * @src: buffer with data content to be written to reg
- * This API will write reg with bytes from src in a single slimbus
- * transaction. All values from 1 to 16 are supported by this API.
- */
-int wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int bytes, void *src)
-{
- int ret = 0;
-
- mutex_lock(&wcd9xxx->io_lock);
- if (wcd9xxx->type == WCD9335) {
- ret = wcd9xxx_page_write(wcd9xxx, &reg);
- if (ret)
- goto err;
-
- ret = __wcd9xxx_slim_write_repeat(wcd9xxx, reg, bytes, src);
- if (ret < 0)
- dev_err(wcd9xxx->dev,
- "%s: Codec repeat write failed (%d)\n",
- __func__, ret);
- } else {
- ret = __wcd9xxx_slim_write_repeat(wcd9xxx, reg, bytes, src);
}
-err:
+
+done:
mutex_unlock(&wcd9xxx->io_lock);
+
return ret;
}
EXPORT_SYMBOL(wcd9xxx_slim_write_repeat);
@@ -839,7 +383,7 @@ EXPORT_SYMBOL(wcd9xxx_slim_write_repeat);
* wcd9xxx_slim_reserve_bw: API to reserve the slimbus bandwidth
* @wcd9xxx: Handle to the wcd9xxx core
* @bw_ops: value of the bandwidth that is requested
- * @commit: Flag to indicate if bandwidth change is to be commited
+ * @commit: Flag to indicate if bandwidth change is to be committed
* right away
*/
int wcd9xxx_slim_reserve_bw(struct wcd9xxx *wcd9xxx,
@@ -856,43 +400,6 @@ int wcd9xxx_slim_reserve_bw(struct wcd9xxx *wcd9xxx,
}
EXPORT_SYMBOL(wcd9xxx_slim_reserve_bw);
-/* Interface specifies whether the write is to the interface or general
- * registers.
- */
-static int wcd9xxx_slim_write_device(struct wcd9xxx *wcd9xxx,
- unsigned short reg, int bytes, void *src, bool interface)
-{
- int ret;
- struct slim_ele_access msg;
- int slim_write_tries = WCD9XXX_SLIM_RW_MAX_TRIES;
- msg.start_offset = WCD9XXX_REGISTER_START_OFFSET + reg;
- msg.num_bytes = bytes;
- msg.comp = NULL;
-
- if (!wcd9xxx->dev_up) {
- dev_dbg_ratelimited(
- wcd9xxx->dev, "%s: No write allowed. dev_up = %d\n",
- __func__, wcd9xxx->dev_up);
- return 0;
- }
-
- while (1) {
- mutex_lock(&wcd9xxx->xfer_lock);
- ret = slim_change_val_element(interface ?
- wcd9xxx->slim_slave : wcd9xxx->slim,
- &msg, src, bytes);
- mutex_unlock(&wcd9xxx->xfer_lock);
- if (likely(ret == 0) || (--slim_write_tries == 0))
- break;
- usleep_range(5000, 5100);
- }
-
- if (ret)
- pr_err("%s: Error, Codec write failed (%d)\n", __func__, ret);
-
- return ret;
-}
-
/*
* wcd9xxx_slim_bulk_write: API to write multiple registers with one descriptor
* @wcd9xxx: Handle to the wcd9xxx core
@@ -963,567 +470,12 @@ mem_fail:
}
EXPORT_SYMBOL(wcd9xxx_slim_bulk_write);
-static struct mfd_cell tabla1x_devs[] = {
- {
- .name = "tabla1x_codec",
- },
-};
-
-static struct mfd_cell tabla_devs[] = {
- {
- .name = "tabla_codec",
- },
-};
-
-static struct mfd_cell sitar_devs[] = {
- {
- .name = "sitar_codec",
- },
-};
-
-static struct mfd_cell taiko_devs[] = {
- {
- .name = "taiko_codec",
- },
-};
-
-static struct mfd_cell tapan_devs[] = {
- {
- .name = "tapan_codec",
- },
-};
-
-static struct mfd_cell tomtom_devs[] = {
- {
- .name = "tomtom_codec",
- },
-};
-
-static struct mfd_cell tasha_devs[] = {
- {
- .name = "tasha_codec",
- },
-};
-
-static const struct wcd9xxx_codec_type wcd9xxx_codecs[] = {
- {
- TABLA_MAJOR, cpu_to_le16(0x1), tabla1x_devs,
- ARRAY_SIZE(tabla1x_devs), TABLA_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x03,
- },
- {
- TABLA_MAJOR, cpu_to_le16(0x2), tabla_devs,
- ARRAY_SIZE(tabla_devs), TABLA_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x03
- },
- {
- /* Siter version 1 has same major chip id with Tabla */
- TABLA_MAJOR, cpu_to_le16(0x0), sitar_devs,
- ARRAY_SIZE(sitar_devs), SITAR_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x01
- },
- {
- SITAR_MAJOR, cpu_to_le16(0x1), sitar_devs,
- ARRAY_SIZE(sitar_devs), SITAR_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x01
- },
- {
- SITAR_MAJOR, cpu_to_le16(0x2), sitar_devs,
- ARRAY_SIZE(sitar_devs), SITAR_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA, 0x01
- },
- {
- TAIKO_MAJOR, cpu_to_le16(0x0), taiko_devs,
- ARRAY_SIZE(taiko_devs), TAIKO_NUM_IRQS, 1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
- },
- {
- TAIKO_MAJOR, cpu_to_le16(0x1), taiko_devs,
- ARRAY_SIZE(taiko_devs), TAIKO_NUM_IRQS, 2,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
- },
- {
- TAPAN_MAJOR, cpu_to_le16(0x0), tapan_devs,
- ARRAY_SIZE(tapan_devs), TAPAN_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x03
- },
- {
- TAPAN_MAJOR, cpu_to_le16(0x1), tapan_devs,
- ARRAY_SIZE(tapan_devs), TAPAN_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x03
- },
- {
- TOMTOM_MAJOR, cpu_to_le16(0x0), tomtom_devs,
- ARRAY_SIZE(tomtom_devs), TOMTOM_NUM_IRQS, 1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
- },
- {
- TOMTOM_MAJOR, cpu_to_le16(0x1), tomtom_devs,
- ARRAY_SIZE(tomtom_devs), TOMTOM_NUM_IRQS, 2,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
- },
- {
- TASHA_MAJOR, cpu_to_le16(0x0), tasha_devs,
- ARRAY_SIZE(tasha_devs), TASHA_NUM_IRQS, -1,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
- },
- {
- TASHA2P0_MAJOR, cpu_to_le16(0x1), tasha_devs,
- ARRAY_SIZE(tasha_devs), TASHA_NUM_IRQS, 2,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO, 0x01
- },
-};
-
-static int wcd9335_bring_up(struct wcd9xxx *wcd9xxx)
-{
- int val, byte0;
- int ret = 0;
-
- val = __wcd9xxx_reg_read(wcd9xxx,
- WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0);
- byte0 = __wcd9xxx_reg_read(wcd9xxx,
- WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0);
-
- if ((val < 0) || (byte0 < 0)) {
- dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n",
- __func__);
- return -EINVAL;
- }
-
- if ((val & 0x80) && (byte0 == 0x0)) {
- dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n",
- __func__);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_CODEC_RPM_RST_CTL, 0x01);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_SIDO_SIDO_CCL_4, 0x21);
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_CODEC_RPM_RST_CTL, 0x3);
- } else if (byte0 == 0x1) {
- dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n",
- __func__);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_CODEC_RPM_RST_CTL, 0x01);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_SIDO_SIDO_TEST_2, 0x00);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_CODEC_RPM_RST_CTL, 0x3);
- } else if ((byte0 == 0) && (!(val & 0x80))) {
- dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n",
- __func__);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_CODEC_RPM_RST_CTL, 0x01);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_SIDO_SIDO_CCL_4, 0x21);
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
- __wcd9xxx_reg_write(wcd9xxx, WCD9335_CODEC_RPM_RST_CTL, 0x3);
- } else {
- dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n",
- __func__);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static void wcd9335_bring_down(struct wcd9xxx *wcd9xxx)
-{
- __wcd9xxx_reg_write(wcd9xxx,
- WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x4);
-}
-
-static int wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
-{
- int ret = 0;
-
- pr_debug("%s: Codec Type: %d\n", __func__, wcd9xxx->type);
-
- if (wcd9xxx->type == WCD9335) {
- ret = wcd9335_bring_up(wcd9xxx);
- } else if (wcd9xxx->type == WCD9330) {
- __wcd9xxx_reg_write(wcd9xxx, WCD9330_A_LEAKAGE_CTL, 0x4);
- __wcd9xxx_reg_write(wcd9xxx, WCD9330_A_CDC_CTL, 0);
- /* wait for 5ms after codec reset for it to complete */
- usleep_range(5000, 5100);
- __wcd9xxx_reg_write(wcd9xxx, WCD9330_A_CDC_CTL, 0x1);
- __wcd9xxx_reg_write(wcd9xxx, WCD9330_A_LEAKAGE_CTL, 0x3);
- __wcd9xxx_reg_write(wcd9xxx, WCD9330_A_CDC_CTL, 0x3);
- } else {
- __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
- __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
- usleep_range(5000, 5100);
- __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
- __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
- }
-
- return ret;
-}
-
-static void wcd9xxx_bring_down(struct wcd9xxx *wcd9xxx)
-{
- unsigned short reg;
-
- if (wcd9xxx->type == WCD9335) {
- wcd9335_bring_down(wcd9xxx);
- return;
- } else if (wcd9xxx->type == WCD9330) {
- reg = WCD9330_A_LEAKAGE_CTL;
- } else
- reg = WCD9XXX_A_LEAKAGE_CTL;
-
- __wcd9xxx_reg_write(wcd9xxx, reg, 0x7);
- __wcd9xxx_reg_write(wcd9xxx, reg, 0x6);
- __wcd9xxx_reg_write(wcd9xxx, reg, 0xe);
- __wcd9xxx_reg_write(wcd9xxx, reg, 0x8);
-}
-
-static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
-{
- int ret;
- struct wcd9xxx_pdata *pdata = wcd9xxx->dev->platform_data;
-
- if (wcd9xxx->wcd_rst_np) {
- /* use pinctrl and call into wcd-rst-gpio driver */
- ret = wcd_gpio_ctrl_select_sleep_state(wcd9xxx->wcd_rst_np);
- if (ret) {
- pr_err("%s: wcd sleep pinctrl state fail!\n",
- __func__);
- return ret;
- }
- /* 20ms sleep required after pulling the reset gpio to LOW */
- msleep(20);
- ret = wcd_gpio_ctrl_select_active_state(wcd9xxx->wcd_rst_np);
- if (ret) {
- pr_err("%s: wcd active pinctrl state fail!\n",
- __func__);
- return ret;
- }
- /* 20ms sleep required after pulling the reset gpio to HIGH */
- msleep(20);
-
- return 0;
- }
-
- if (wcd9xxx->reset_gpio && wcd9xxx->dev_up
- && !pdata->use_pinctrl) {
- ret = gpio_request(wcd9xxx->reset_gpio, "CDC_RESET");
- if (ret) {
- pr_err("%s: Failed to request gpio %d\n", __func__,
- wcd9xxx->reset_gpio);
- wcd9xxx->reset_gpio = 0;
- return ret;
- }
- }
- if (wcd9xxx->reset_gpio) {
- if (pdata->use_pinctrl) {
- /* Reset the CDC PDM TLMM pins to a default state */
- ret = pinctrl_select_state(pinctrl_info.pinctrl,
- pinctrl_info.extncodec_sus);
- if (ret != 0) {
- pr_err("%s: Failed to suspend reset pins, ret: %d\n",
- __func__, ret);
- return ret;
- }
- msleep(20);
- ret = pinctrl_select_state(pinctrl_info.pinctrl,
- pinctrl_info.extncodec_act);
- if (ret != 0) {
- pr_err("%s: Failed to enable gpio pins; ret=%d\n",
- __func__, ret);
- return ret;
- }
- msleep(20);
- } else {
- gpio_direction_output(wcd9xxx->reset_gpio, 0);
- msleep(20);
- gpio_direction_output(wcd9xxx->reset_gpio, 1);
- msleep(20);
- }
- }
- return 0;
-}
-
-static void wcd9xxx_free_reset(struct wcd9xxx *wcd9xxx)
-{
- struct wcd9xxx_pdata *pdata = wcd9xxx->dev->platform_data;
-
- if (wcd9xxx->wcd_rst_np) {
- wcd_gpio_ctrl_select_sleep_state(wcd9xxx->wcd_rst_np);
- return;
- }
-
- if (wcd9xxx->reset_gpio) {
- if (!pdata->use_pinctrl) {
- gpio_free(wcd9xxx->reset_gpio);
- wcd9xxx->reset_gpio = 0;
- } else
- pinctrl_put(pinctrl_info.pinctrl);
- }
-}
-
-static void wcd9xxx_chip_version_ctrl_reg(struct wcd9xxx *wcd9xxx,
- unsigned int *byte_0,
- unsigned int *byte_1,
- unsigned int *byte_2)
-{
- switch (wcd9xxx->type) {
- case WCD9335:
- *byte_0 = WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0;
- *byte_1 = WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1;
- *byte_2 = WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2;
- break;
- case WCD9330:
- case WCD9XXX:
- default:
- *byte_0 = WCD9XXX_A_CHIP_ID_BYTE_0;
- *byte_1 = WCD9XXX_A_CHIP_ID_BYTE_1;
- *byte_2 = WCD9XXX_A_CHIP_ID_BYTE_2;
- break;
- }
-
- return;
-}
-
-static const struct wcd9xxx_codec_type
-*wcd9xxx_check_codec_type(struct wcd9xxx *wcd9xxx, u8 *version)
-{
- int i, rc;
- const struct wcd9xxx_codec_type *c, *d = NULL;
- unsigned int byte_0, byte_1, byte_2;
-
- wcd9xxx_chip_version_ctrl_reg(wcd9xxx, &byte_0, &byte_1, &byte_2);
-
- rc = __wcd9xxx_bulk_read(wcd9xxx, byte_0,
- sizeof(wcd9xxx->id_minor),
- (u8 *)&wcd9xxx->id_minor);
- if (rc < 0)
- goto exit;
-
- rc = __wcd9xxx_bulk_read(wcd9xxx, byte_2,
- sizeof(wcd9xxx->id_major),
- (u8 *)&wcd9xxx->id_major);
- if (rc < 0)
- goto exit;
- dev_dbg(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
- __func__, wcd9xxx->id_major, wcd9xxx->id_minor);
-
- for (i = 0, c = &wcd9xxx_codecs[0]; i < ARRAY_SIZE(wcd9xxx_codecs);
- i++, c++) {
- if (c->id_major == wcd9xxx->id_major) {
- if (c->id_minor == wcd9xxx->id_minor) {
- d = c;
- dev_dbg(wcd9xxx->dev,
- "%s: exact match %s\n", __func__,
- d->dev->name);
- break;
- } else if (!d) {
- d = c;
- } else {
- if ((d->id_minor < c->id_minor) ||
- (d->id_minor == c->id_minor &&
- d->version < c->version))
- d = c;
- }
- dev_dbg(wcd9xxx->dev,
- "%s: best match %s, major 0x%x, minor 0x%x\n",
- __func__, d->dev->name, d->id_major,
- d->id_minor);
- }
- }
-
- if (!d) {
- dev_warn(wcd9xxx->dev,
- "%s: driver for id major 0x%x, minor 0x%x not found\n",
- __func__, wcd9xxx->id_major, wcd9xxx->id_minor);
- } else {
- if (d->version > -1) {
- *version = d->version;
- } else if (d->id_major == TASHA_MAJOR) {
- rc = __wcd9xxx_reg_read(wcd9xxx,
- WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0);
- if (rc < 0) {
- d = NULL;
- goto exit;
- }
- *version = ((u8)rc & 0x80) >> 7;
- } else {
- rc = __wcd9xxx_reg_read(wcd9xxx,
- WCD9XXX_A_CHIP_VERSION);
- if (rc < 0) {
- d = NULL;
- goto exit;
- }
- *version = (u8)rc & 0x1F;
- }
- dev_info(wcd9xxx->dev,
- "%s: detected %s, major 0x%x, minor 0x%x, ver 0x%x\n",
- __func__, d->dev->name, d->id_major, d->id_minor,
- *version);
- }
-exit:
- return d;
-}
-
static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
{
return (wcd9xxx->codec_type->num_irqs / 8) +
((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
}
-/*
- * Interrupt table for v1 corresponds to newer version
- * codecs (wcd9304 and wcd9310)
- */
-static const struct intr_data intr_tbl_v1[] = {
- {WCD9XXX_IRQ_SLIMBUS, false},
- {WCD9XXX_IRQ_MBHC_INSERTION, true},
- {WCD9XXX_IRQ_MBHC_POTENTIAL, true},
- {WCD9XXX_IRQ_MBHC_RELEASE, true},
- {WCD9XXX_IRQ_MBHC_PRESS, true},
- {WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
- {WCD9XXX_IRQ_MBHC_REMOVAL, true},
- {WCD9XXX_IRQ_BG_PRECHARGE, false},
- {WCD9XXX_IRQ_PA1_STARTUP, false},
- {WCD9XXX_IRQ_PA2_STARTUP, false},
- {WCD9XXX_IRQ_PA3_STARTUP, false},
- {WCD9XXX_IRQ_PA4_STARTUP, false},
- {WCD9XXX_IRQ_PA5_STARTUP, false},
- {WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
- {WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
- {WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
- {WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
- {WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
- {WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
- {WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
- {WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
- {WCD9320_IRQ_EAR_PA_STARTUP, false},
- {WCD9XXX_IRQ_RESERVED_0, false},
- {WCD9XXX_IRQ_RESERVED_1, false},
-};
-
-/*
- * Interrupt table for v2 corresponds to newer version
- * codecs (wcd9320 and wcd9306)
- */
-static const struct intr_data intr_tbl_v2[] = {
- {WCD9XXX_IRQ_SLIMBUS, false},
- {WCD9XXX_IRQ_MBHC_INSERTION, true},
- {WCD9XXX_IRQ_MBHC_POTENTIAL, true},
- {WCD9XXX_IRQ_MBHC_RELEASE, true},
- {WCD9XXX_IRQ_MBHC_PRESS, true},
- {WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
- {WCD9XXX_IRQ_MBHC_REMOVAL, true},
- {WCD9320_IRQ_MBHC_JACK_SWITCH, true},
- {WCD9306_IRQ_MBHC_JACK_SWITCH, true},
- {WCD9XXX_IRQ_BG_PRECHARGE, false},
- {WCD9XXX_IRQ_PA1_STARTUP, false},
- {WCD9XXX_IRQ_PA2_STARTUP, false},
- {WCD9XXX_IRQ_PA3_STARTUP, false},
- {WCD9XXX_IRQ_PA4_STARTUP, false},
- {WCD9306_IRQ_HPH_PA_OCPR_FAULT, false},
- {WCD9XXX_IRQ_PA5_STARTUP, false},
- {WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
- {WCD9306_IRQ_HPH_PA_OCPL_FAULT, false},
- {WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
- {WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
- {WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
- {WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
- {WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
- {WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
- {WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
- {WCD9XXX_IRQ_RESERVED_0, false},
- {WCD9XXX_IRQ_RESERVED_1, false},
- {WCD9XXX_IRQ_MAD_AUDIO, false},
- {WCD9XXX_IRQ_MAD_BEACON, false},
- {WCD9XXX_IRQ_MAD_ULTRASOUND, false},
- {WCD9XXX_IRQ_SPEAKER_CLIPPING, false},
- {WCD9XXX_IRQ_VBAT_MONITOR_ATTACK, false},
- {WCD9XXX_IRQ_VBAT_MONITOR_RELEASE, false},
-};
-
-/*
- * Interrupt table for v3 corresponds to newer version
- * codecs (wcd9330)
- */
-static const struct intr_data intr_tbl_v3[] = {
- {WCD9XXX_IRQ_SLIMBUS, false},
- {WCD9XXX_IRQ_MBHC_INSERTION, true},
- {WCD9XXX_IRQ_MBHC_POTENTIAL, true},
- {WCD9XXX_IRQ_MBHC_RELEASE, true},
- {WCD9XXX_IRQ_MBHC_PRESS, true},
- {WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
- {WCD9XXX_IRQ_MBHC_REMOVAL, true},
- {WCD9330_IRQ_MBHC_JACK_SWITCH, true},
- {WCD9XXX_IRQ_BG_PRECHARGE, false},
- {WCD9XXX_IRQ_PA1_STARTUP, false},
- {WCD9XXX_IRQ_PA2_STARTUP, false},
- {WCD9XXX_IRQ_PA3_STARTUP, false},
- {WCD9XXX_IRQ_PA4_STARTUP, false},
- {WCD9XXX_IRQ_PA5_STARTUP, false},
- {WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
- {WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
- {WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
- {WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
- {WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
- {WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
- {WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
- {WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
- {WCD9320_IRQ_EAR_PA_STARTUP, false},
- {WCD9330_IRQ_SVASS_ERR_EXCEPTION, false},
- {WCD9330_IRQ_SVASS_ENGINE, true},
- {WCD9330_IRQ_MAD_AUDIO, false},
- {WCD9330_IRQ_MAD_BEACON, false},
- {WCD9330_IRQ_MAD_ULTRASOUND, false},
- {WCD9330_IRQ_SPEAKER1_CLIPPING, false},
- {WCD9330_IRQ_SPEAKER2_CLIPPING, false},
- {WCD9330_IRQ_VBAT_MONITOR_ATTACK, false},
- {WCD9330_IRQ_VBAT_MONITOR_RELEASE, false},
-};
-
-/*
- * Interrupt table for v4 corresponds to newer version
- * codecs (wcd9335)
- */
-static const struct intr_data intr_tbl_v4[] = {
- {WCD9XXX_IRQ_SLIMBUS, false},
- {WCD9335_IRQ_MBHC_SW_DET, true},
- {WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true},
- {WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true},
- {WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true},
- {WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
- {WCD9335_IRQ_FLL_LOCK_LOSS, false},
- {WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false},
- {WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false},
- {WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false},
- {WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false},
- {WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false},
- {WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false},
- {WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false},
- {WCD9335_IRQ_HPH_PA_OCPL_FAULT, false},
- {WCD9335_IRQ_HPH_PA_OCPR_FAULT, false},
- {WCD9335_IRQ_EAR_PA_OCP_FAULT, false},
- {WCD9335_IRQ_SOUNDWIRE, false},
- {WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false},
- {WCD9335_IRQ_RCO_ERROR, false},
- {WCD9335_IRQ_SVA_ERROR, false},
- {WCD9335_IRQ_MAD_AUDIO, false},
- {WCD9335_IRQ_MAD_BEACON, false},
- {WCD9335_IRQ_SVA_OUTBOX1, true},
- {WCD9335_IRQ_SVA_OUTBOX2, true},
- {WCD9335_IRQ_MAD_ULTRASOUND, false},
- {WCD9335_IRQ_VBAT_ATTACK, false},
- {WCD9335_IRQ_VBAT_RESTORE, false},
-};
-
static int wcd9xxx_regmap_init_cache(struct wcd9xxx *wcd9xxx)
{
struct regmap_config *regmap_config;
@@ -1544,118 +496,69 @@ static int wcd9xxx_regmap_init_cache(struct wcd9xxx *wcd9xxx)
return rc;
}
-static void wcd9xxx_core_res_update_irq_regs(
- struct wcd9xxx_core_resource *core_res,
- u16 id_major)
-{
- switch (id_major) {
- case TASHA_MAJOR:
- case TASHA2P0_MAJOR:
- core_res->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
- WCD9335_INTR_PIN1_STATUS0;
- core_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
- WCD9335_INTR_PIN1_CLEAR0;
- core_res->intr_reg[WCD9XXX_INTR_MASK_BASE] =
- WCD9335_INTR_PIN1_MASK0;
- core_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
- WCD9335_INTR_LEVEL0;
- core_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
- WCD9335_INTR_CLR_COMMIT;
- break;
- case TABLA_MAJOR:
- case TOMTOM_MAJOR:
- case TAIKO_MAJOR:
- default:
- core_res->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
- WCD9XXX_A_INTR_STATUS0;
- core_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
- WCD9XXX_A_INTR_CLEAR0;
- core_res->intr_reg[WCD9XXX_INTR_MASK_BASE] =
- WCD9XXX_A_INTR_MASK0;
- core_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
- WCD9XXX_A_INTR_LEVEL0;
- core_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
- WCD9XXX_A_INTR_MODE;
- break;
- };
-}
-
static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
{
- int ret = 0;
- u8 version;
- const struct wcd9xxx_codec_type *found;
+ int ret = 0, i;
struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
regmap_patch_fptr regmap_apply_patch = NULL;
mutex_init(&wcd9xxx->io_lock);
mutex_init(&wcd9xxx->xfer_lock);
- dev_set_drvdata(wcd9xxx->dev, wcd9xxx);
- ret = wcd9xxx_bring_up(wcd9xxx);
+ ret = wcd9xxx_bringup(wcd9xxx->dev);
if (ret) {
ret = -EPROBE_DEFER;
goto err_bring_up;
}
- found = wcd9xxx_check_codec_type(wcd9xxx, &version);
- if (!found) {
- ret = -ENODEV;
- goto err;
- } else {
- wcd9xxx->codec_type = found;
- wcd9xxx->version = version;
+ wcd9xxx->codec_type = devm_kzalloc(wcd9xxx->dev,
+ sizeof(struct wcd9xxx_codec_type), GFP_KERNEL);
+ if (!wcd9xxx->codec_type) {
+ ret = -ENOMEM;
+ goto err_bring_up;
+ }
+ ret = wcd9xxx_get_codec_info(wcd9xxx->dev);
+ if (ret) {
+ ret = -EPROBE_DEFER;
+ goto fail_cdc_fill;
}
+ wcd9xxx->version = wcd9xxx->codec_type->version;
+ if (!wcd9xxx->codec_type->dev || !wcd9xxx->codec_type->size)
+ goto fail_cdc_fill;
core_res->parent = wcd9xxx;
core_res->dev = wcd9xxx->dev;
+ core_res->intr_table = wcd9xxx->codec_type->intr_tbl;
+ core_res->intr_table_size = wcd9xxx->codec_type->intr_tbl_size;
- if (wcd9xxx->codec_type->id_major == TABLA_MAJOR
- || wcd9xxx->codec_type->id_major == SITAR_MAJOR) {
- core_res->intr_table = intr_tbl_v1;
- core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v1);
- } else if (wcd9xxx->codec_type->id_major == TOMTOM_MAJOR) {
- core_res->intr_table = intr_tbl_v3;
- core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v3);
- } else if ((wcd9xxx->codec_type->id_major == TASHA_MAJOR) ||
- (wcd9xxx->codec_type->id_major == TASHA2P0_MAJOR)) {
- core_res->intr_table = intr_tbl_v4;
- core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v4);
- } else {
- core_res->intr_table = intr_tbl_v2;
- core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v2);
- }
- wcd9xxx_core_res_update_irq_regs(&wcd9xxx->core_res,
- wcd9xxx->codec_type->id_major);
+ for (i = 0; i < WCD9XXX_INTR_REG_MAX; i++)
+ wcd9xxx->core_res.intr_reg[i] =
+ wcd9xxx->codec_type->intr_reg[i];
wcd9xxx_core_res_init(&wcd9xxx->core_res,
- wcd9xxx->codec_type->num_irqs,
- wcd9xxx_num_irq_regs(wcd9xxx),
- wcd9xxx_reg_read, wcd9xxx_reg_write,
- wcd9xxx_bulk_read, wcd9xxx_bulk_write);
+ wcd9xxx->codec_type->num_irqs,
+ wcd9xxx_num_irq_regs(wcd9xxx),
+ wcd9xxx->regmap);
if (wcd9xxx_core_irq_init(&wcd9xxx->core_res))
goto err;
- /* If codec uses regmap, initialize regmap register cache */
- if (wcd9xxx->using_regmap) {
- ret = wcd9xxx_regmap_init_cache(wcd9xxx);
+ ret = wcd9xxx_regmap_init_cache(wcd9xxx);
+ if (ret)
+ goto err_irq;
+
+ regmap_apply_patch = wcd9xxx_get_regmap_reg_patch(
+ wcd9xxx->type);
+ if (regmap_apply_patch) {
+ ret = regmap_apply_patch(wcd9xxx->regmap,
+ wcd9xxx->version);
if (ret)
- goto err_irq;
-
- regmap_apply_patch = wcd9xxx_get_regmap_reg_patch(
- wcd9xxx->type);
- if (regmap_apply_patch) {
- ret = regmap_apply_patch(wcd9xxx->regmap,
- wcd9xxx->version);
- if (ret)
- dev_err(wcd9xxx->dev,
+ dev_err(wcd9xxx->dev,
"Failed to register patch: %d\n", ret);
- }
}
- ret = mfd_add_devices(wcd9xxx->dev, -1, found->dev, found->size,
- NULL, 0, NULL);
+ ret = mfd_add_devices(wcd9xxx->dev, -1, wcd9xxx->codec_type->dev,
+ wcd9xxx->codec_type->size, NULL, 0, NULL);
if (ret != 0) {
dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
goto err_irq;
@@ -1670,8 +573,11 @@ static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
return ret;
err_irq:
wcd9xxx_irq_exit(&wcd9xxx->core_res);
+fail_cdc_fill:
+ devm_kfree(wcd9xxx->dev, wcd9xxx->codec_type);
+ wcd9xxx->codec_type = NULL;
err:
- wcd9xxx_bring_down(wcd9xxx);
+ wcd9xxx_bringdown(wcd9xxx->dev);
wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
err_bring_up:
mutex_destroy(&wcd9xxx->io_lock);
@@ -1683,14 +589,13 @@ static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
{
device_init_wakeup(wcd9xxx->dev, false);
wcd9xxx_irq_exit(&wcd9xxx->core_res);
- wcd9xxx_bring_down(wcd9xxx);
- wcd9xxx_free_reset(wcd9xxx);
+ wcd9xxx_bringdown(wcd9xxx->dev);
+ wcd9xxx_reset_low(wcd9xxx->dev);
wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
mutex_destroy(&wcd9xxx->io_lock);
mutex_destroy(&wcd9xxx->xfer_lock);
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
slim_remove_device(wcd9xxx->slim_slave);
- kfree(wcd9xxx);
}
@@ -1786,33 +691,23 @@ static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
return ret_cnt;
}
-/*
- * Place inside CONFIG_DEBUG section as this function is only used by debugfs
- * function
- */
static void wcd9xxx_set_reset_pin_state(struct wcd9xxx *wcd9xxx,
struct wcd9xxx_pdata *pdata,
bool active)
{
if (wcd9xxx->wcd_rst_np) {
if (active)
- wcd_gpio_ctrl_select_active_state(wcd9xxx->wcd_rst_np);
+ msm_cdc_pinctrl_select_active_state(
+ wcd9xxx->wcd_rst_np);
else
- wcd_gpio_ctrl_select_sleep_state(wcd9xxx->wcd_rst_np);
+ msm_cdc_pinctrl_select_sleep_state(
+ wcd9xxx->wcd_rst_np);
return;
- }
-
- if (pdata->use_pinctrl) {
- if (active == true)
- pinctrl_select_state(pinctrl_info.pinctrl,
- pinctrl_info.extncodec_act);
- else
- pinctrl_select_state(pinctrl_info.pinctrl,
- pinctrl_info.extncodec_sus);
- } else
+ } else if (gpio_is_valid(wcd9xxx->reset_gpio)) {
gpio_direction_output(wcd9xxx->reset_gpio,
(active == true ? 1 : 0));
+ }
}
static int codec_debug_process_cdc_power(char *lbuf)
@@ -1833,10 +728,16 @@ static int codec_debug_process_cdc_power(char *lbuf)
pdata = debugCodec->slim->dev.platform_data;
if (param == 0) {
wcd9xxx_slim_device_down(debugCodec->slim);
- wcd9xxx_disable_supplies(debugCodec, pdata);
+ msm_cdc_disable_static_supplies(debugCodec->dev,
+ debugCodec->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
wcd9xxx_set_reset_pin_state(debugCodec, pdata, false);
} else if (param == 1) {
- wcd9xxx_enable_static_supplies(debugCodec, pdata);
+ msm_cdc_enable_static_supplies(debugCodec->dev,
+ debugCodec->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
usleep_range(1000, 2000);
wcd9xxx_set_reset_pin_state(debugCodec, pdata, false);
usleep_range(1000, 2000);
@@ -1905,144 +806,6 @@ static const struct file_operations codec_debug_ops = {
};
#endif
-static int wcd9xxx_init_supplies(struct wcd9xxx *wcd9xxx,
- struct wcd9xxx_pdata *pdata)
-{
- int ret;
- int i;
- wcd9xxx->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
- ARRAY_SIZE(pdata->regulator),
- GFP_KERNEL);
- if (!wcd9xxx->supplies) {
- ret = -ENOMEM;
- goto err;
- }
-
- wcd9xxx->num_of_supplies = 0;
-
- if (ARRAY_SIZE(pdata->regulator) > WCD9XXX_MAX_REGULATOR) {
- pr_err("%s: Array Size out of bound\n", __func__);
- ret = -EINVAL;
- goto err;
- }
-
- for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
- if (pdata->regulator[i].name) {
- wcd9xxx->supplies[i].supply = pdata->regulator[i].name;
- wcd9xxx->num_of_supplies++;
- }
- }
-
- ret = regulator_bulk_get(wcd9xxx->dev, wcd9xxx->num_of_supplies,
- wcd9xxx->supplies);
- if (ret != 0) {
- dev_err(wcd9xxx->dev, "Failed to get supplies: err = %d\n",
- ret);
- goto err_supplies;
- }
-
- for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
- if (regulator_count_voltages(wcd9xxx->supplies[i].consumer) <=
- 0)
- continue;
- ret = regulator_set_voltage(wcd9xxx->supplies[i].consumer,
- pdata->regulator[i].min_uV,
- pdata->regulator[i].max_uV);
- if (ret) {
- pr_err("%s: Setting regulator voltage failed for regulator %s err = %d\n",
- __func__,
- wcd9xxx->supplies[i].supply, ret);
- goto err_get;
- }
-
- ret = regulator_set_load(wcd9xxx->supplies[i].consumer,
- pdata->regulator[i].optimum_uA);
- if (ret < 0) {
- pr_err("%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
- __func__,
- wcd9xxx->supplies[i].supply, ret);
- goto err_get;
- } else {
- ret = 0;
- }
- }
-
- return ret;
-
-err_get:
- regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
-err_supplies:
- kfree(wcd9xxx->supplies);
-err:
- return ret;
-}
-
-static int wcd9xxx_enable_static_supplies(struct wcd9xxx *wcd9xxx,
- struct wcd9xxx_pdata *pdata)
-{
- int i;
- int ret = 0;
-
- for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
- if (pdata->regulator[i].ondemand)
- continue;
- ret = regulator_enable(wcd9xxx->supplies[i].consumer);
- if (ret) {
- pr_err("%s: Failed to enable %s\n", __func__,
- wcd9xxx->supplies[i].supply);
- break;
- } else {
- pr_debug("%s: Enabled regulator %s\n", __func__,
- wcd9xxx->supplies[i].supply);
- }
- }
-
- while (ret && --i)
- if (!pdata->regulator[i].ondemand)
- regulator_disable(wcd9xxx->supplies[i].consumer);
-
- return ret;
-}
-
-static void wcd9xxx_disable_supplies(struct wcd9xxx *wcd9xxx,
- struct wcd9xxx_pdata *pdata)
-{
- int i;
- int rc;
-
- for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
- if (pdata->regulator[i].ondemand)
- continue;
- rc = regulator_disable(wcd9xxx->supplies[i].consumer);
- if (rc) {
- pr_err("%s: Failed to disable %s\n", __func__,
- wcd9xxx->supplies[i].supply);
- } else {
- pr_debug("%s: Disabled regulator %s\n", __func__,
- wcd9xxx->supplies[i].supply);
- }
- }
-}
-
-static void wcd9xxx_release_supplies(struct wcd9xxx *wcd9xxx,
- struct wcd9xxx_pdata *pdata)
-{
- int i;
-
- wcd9xxx_disable_supplies(wcd9xxx, pdata);
-
- for (i = 0; i < wcd9xxx->num_of_supplies; i++) {
- if (regulator_count_voltages(wcd9xxx->supplies[i].consumer) <=
- 0)
- continue;
- regulator_set_voltage(wcd9xxx->supplies[i].consumer, 0,
- pdata->regulator[i].max_uV);
- regulator_set_load(wcd9xxx->supplies[i].consumer, 0);
- }
- regulator_bulk_free(wcd9xxx->num_of_supplies, wcd9xxx->supplies);
- kfree(wcd9xxx->supplies);
-}
-
static struct wcd9xxx_i2c *wcd9xxx_i2c_get_device_info(struct wcd9xxx *wcd9xxx,
u16 reg)
{
@@ -2173,6 +936,7 @@ static int wcd9xxx_i2c_get_client_index(struct i2c_client *client,
int *wcd9xx_index)
{
int ret = 0;
+
switch (client->addr) {
case WCD9XXX_I2C_TOP_SLAVE_ADDR:
*wcd9xx_index = WCD9XXX_I2C_TOP_LEVEL;
@@ -2229,7 +993,7 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
if (client->dev.of_node) {
dev_dbg(&client->dev, "%s:Platform data\n"
"from device tree\n", __func__);
- pdata = wcd9xxx_populate_dt_pdata(&client->dev);
+ pdata = wcd9xxx_populate_dt_data(&client->dev);
if (!pdata) {
dev_err(&client->dev,
"%s: Fail to obtain pdata from device tree\n",
@@ -2243,9 +1007,9 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
"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__);
+ wcd9xxx = devm_kzalloc(&client->dev, sizeof(struct wcd9xxx),
+ GFP_KERNEL);
+ if (!wcd9xxx) {
ret = -ENOMEM;
goto fail;
}
@@ -2268,28 +1032,22 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
__func__);
wcd9xxx->type = WCD9XXX;
}
- wcd9xxx_set_codec_specific_param(wcd9xxx);
- if (wcd9xxx->using_regmap) {
- wcd9xxx->regmap = devm_regmap_init_i2c_bus(client,
- &wcd9xxx_i2c_base_regmap_config);
- if (IS_ERR(wcd9xxx->regmap)) {
- ret = PTR_ERR(wcd9xxx->regmap);
- dev_err(&client->dev, "%s: Failed to allocate register map: %d\n",
+ wcd9xxx->regmap = wcd9xxx_regmap_init(&client->dev,
+ &wcd9xxx_i2c_base_regmap_config);
+ if (IS_ERR(wcd9xxx->regmap)) {
+ ret = PTR_ERR(wcd9xxx->regmap);
+ dev_err(&client->dev, "%s: Failed to allocate register map: %d\n",
__func__, ret);
- goto err_codec;
- }
+ goto err_codec;
}
wcd9xxx->reset_gpio = pdata->reset_gpio;
wcd9xxx->wcd_rst_np = pdata->wcd_rst_np;
if (!wcd9xxx->wcd_rst_np) {
- ret = extcodec_get_pinctrl(&client->dev);
- if (ret < 0)
- pdata->use_pinctrl = false;
- else
- pdata->use_pinctrl = true;
- } else {
- pdata->use_pinctrl = true;
+ pdata->use_pinctrl = false;
+ dev_err(&client->dev, "%s: pinctrl not used for rst_n\n",
+ __func__);
+ goto err_codec;
}
if (i2c_check_functionality(client->adapter,
@@ -2304,17 +1062,22 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
if (client->dev.of_node)
wcd9xxx->mclk_rate = pdata->mclk_rate;
- ret = wcd9xxx_init_supplies(wcd9xxx, pdata);
- if (ret) {
- pr_err("%s: Fail to enable Codec supplies\n",
- __func__);
+ wcd9xxx->num_of_supplies = pdata->num_supplies;
+ ret = msm_cdc_init_supplies(wcd9xxx->dev, &wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
+ if (!wcd9xxx->supplies) {
+ dev_err(wcd9xxx->dev, "%s: Cannot init wcd supplies\n",
+ __func__);
goto err_codec;
}
-
- ret = wcd9xxx_enable_static_supplies(wcd9xxx, pdata);
+ ret = msm_cdc_enable_static_supplies(wcd9xxx->dev,
+ wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
if (ret) {
- pr_err("%s: Fail to enable Codec pre-reset supplies\n",
- __func__);
+ dev_err(wcd9xxx->dev, "%s: wcd static supply enable failed!\n",
+ __func__);
goto err_codec;
}
/* For WCD9335, it takes about 600us for the Vout_A and
@@ -2326,7 +1089,7 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
else
usleep_range(5, 10);
- ret = wcd9xxx_reset(wcd9xxx);
+ ret = wcd9xxx_reset(wcd9xxx->dev);
if (ret) {
pr_err("%s: Resetting Codec failed\n", __func__);
goto err_supplies;
@@ -2342,7 +1105,7 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
wcd9xxx->read_dev = wcd9xxx_i2c_read;
wcd9xxx->write_dev = wcd9xxx_i2c_write;
if (!wcd9xxx->dev->of_node)
- wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+ wcd9xxx_assign_irq(&wcd9xxx->core_res,
pdata->irq, pdata->irq_base);
ret = wcd9xxx_device_init(wcd9xxx);
@@ -2352,7 +1115,8 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
goto err_device_init;
}
- ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
+ ret = wcd9xxx_i2c_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1,
+ &val, 0);
if (ret < 0)
pr_err("%s: failed to read the wcd9xxx status (%d)\n",
__func__, ret);
@@ -2367,11 +1131,15 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
err_device_init:
- wcd9xxx_free_reset(wcd9xxx);
+ wcd9xxx_reset_low(wcd9xxx->dev);
err_supplies:
- wcd9xxx_release_supplies(wcd9xxx, pdata);
+ msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
+ pdata->regulator = NULL;
+ pdata->num_supplies = 0;
err_codec:
- kfree(wcd9xxx);
+ devm_kfree(&client->dev, wcd9xxx);
dev_set_drvdata(&client->dev, NULL);
fail:
return ret;
@@ -2381,173 +1149,16 @@ static int wcd9xxx_i2c_remove(struct i2c_client *client)
{
struct wcd9xxx *wcd9xxx;
struct wcd9xxx_pdata *pdata = client->dev.platform_data;
- pr_debug("exit\n");
+
wcd9xxx = dev_get_drvdata(&client->dev);
- wcd9xxx_release_supplies(wcd9xxx, pdata);
+ msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
wcd9xxx_device_exit(wcd9xxx);
dev_set_drvdata(&client->dev, NULL);
return 0;
}
-static int wcd9xxx_dt_parse_vreg_info(struct device *dev,
- struct wcd9xxx_regulator *vreg,
- const char *vreg_name,
- bool ondemand)
-{
- int len, ret = 0;
- const __be32 *prop;
- char prop_name[CODEC_DT_MAX_PROP_SIZE];
- struct device_node *regnode = NULL;
- u32 prop_val;
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
- vreg_name);
- regnode = of_parse_phandle(dev->of_node, prop_name, 0);
-
- if (!regnode) {
- dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
- return -ENODEV;
- }
- vreg->name = vreg_name;
- vreg->ondemand = ondemand;
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,%s-voltage", vreg_name);
- prop = of_get_property(dev->of_node, prop_name, &len);
-
- if (!prop || (len != (2 * sizeof(__be32)))) {
- dev_err(dev, "%s %s property\n",
- prop ? "invalid format" : "no", prop_name);
- return -EINVAL;
- } else {
- vreg->min_uV = be32_to_cpup(&prop[0]);
- vreg->max_uV = be32_to_cpup(&prop[1]);
- }
-
- snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
- "qcom,%s-current", vreg_name);
-
- ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed",
- prop_name, dev->of_node->full_name);
- return -EFAULT;
- }
- vreg->optimum_uA = prop_val;
-
- dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n", vreg->name,
- vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
- return 0;
-}
-
-static int wcd9xxx_read_of_property_u32(struct device *dev,
- const char *name, u32 *val)
-{
- int ret = 0;
- ret = of_property_read_u32(dev->of_node, name, val);
- if (ret)
- dev_err(dev, "Looking up %s property in node %s failed",
- name, dev->of_node->full_name);
- return ret;
-}
-
-static int wcd9xxx_dt_parse_micbias_info(struct device *dev,
- struct wcd9xxx_micbias_setting *micbias)
-{
- u32 prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias-ldoh-v",
- &prop_val)))
- micbias->ldoh_v = (u8)prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias-cfilt1-mv",
- &prop_val)))
- micbias->cfilt1_mv = prop_val;
- else if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias1-mv",
- &prop_val)))
- micbias->micb1_mv = prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias-cfilt2-mv",
- &prop_val)))
- micbias->cfilt2_mv = prop_val;
- else if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias2-mv",
- &prop_val)))
- micbias->micb2_mv = prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias-cfilt3-mv",
- &prop_val)))
- micbias->cfilt3_mv = prop_val;
- else if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias3-mv",
- &prop_val)))
- micbias->micb3_mv = prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias4-mv",
- &prop_val)))
- micbias->micb4_mv = prop_val;
-
- /* Read micbias values for codec. Does not matter even if a few
- * micbias values are not defined in the Device Tree. Codec will
- * anyway not use those values
- */
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias1-cfilt-sel",
- &prop_val)))
- micbias->bias1_cfilt_sel = (u8)prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias2-cfilt-sel",
- &prop_val)))
- micbias->bias2_cfilt_sel = (u8)prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias3-cfilt-sel",
- &prop_val)))
- micbias->bias3_cfilt_sel = (u8)prop_val;
-
- if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-micbias4-cfilt-sel",
- &prop_val)))
- micbias->bias4_cfilt_sel = (u8)prop_val;
-
- /* micbias external cap */
- micbias->bias1_cap_mode =
- (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
- MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
- micbias->bias2_cap_mode =
- (of_property_read_bool(dev->of_node, "qcom,cdc-micbias2-ext-cap") ?
- MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
- micbias->bias3_cap_mode =
- (of_property_read_bool(dev->of_node, "qcom,cdc-micbias3-ext-cap") ?
- MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
- micbias->bias4_cap_mode =
- (of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ?
- MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
-
- micbias->bias2_is_headset_only =
- of_property_read_bool(dev->of_node,
- "qcom,cdc-micbias2-headset-only");
-
- dev_dbg(dev, "ldoh_v %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
- (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv,
- (u32)micbias->cfilt2_mv, (u32)micbias->cfilt3_mv);
-
- dev_dbg(dev, "micb1_mv %u micb2_mv %u micb3_mv %u micb4_mv %u",
- micbias->micb1_mv, micbias->micb2_mv,
- micbias->micb3_mv, micbias->micb4_mv);
-
- dev_dbg(dev, "bias1_cfilt_sel %u bias2_cfilt_sel %u\n",
- (u32)micbias->bias1_cfilt_sel, (u32)micbias->bias2_cfilt_sel);
-
- dev_dbg(dev, "bias3_cfilt_sel %u bias4_cfilt_sel %u\n",
- (u32)micbias->bias3_cfilt_sel, (u32)micbias->bias4_cfilt_sel);
-
- dev_dbg(dev, "bias1_ext_cap %d bias2_ext_cap %d\n",
- micbias->bias1_cap_mode, micbias->bias2_cap_mode);
- dev_dbg(dev, "bias3_ext_cap %d bias4_ext_cap %d\n",
- micbias->bias3_cap_mode, micbias->bias4_cap_mode);
-
- dev_dbg(dev, "bias2_is_headset_only %d\n",
- micbias->bias2_is_headset_only);
- return 0;
-}
-
static int wcd9xxx_dt_parse_slim_interface_dev_info(struct device *dev,
struct slim_device *slim_ifd)
{
@@ -2578,268 +1189,6 @@ static int wcd9xxx_dt_parse_slim_interface_dev_info(struct device *dev,
return 0;
}
-static int wcd9xxx_process_supplies(struct device *dev,
- struct wcd9xxx_pdata *pdata, const char *supply_list,
- int supply_cnt, bool is_ondemand, int index)
-{
- int idx, ret = 0;
- const char *name;
-
- if (supply_cnt == 0) {
- dev_dbg(dev, "%s: no supplies defined for %s\n", __func__,
- supply_list);
- return 0;
- }
-
- for (idx = 0; idx < supply_cnt; idx++) {
- ret = of_property_read_string_index(dev->of_node,
- supply_list, idx,
- &name);
- if (ret) {
- dev_err(dev, "%s: of read string %s idx %d error %d\n",
- __func__, supply_list, idx, ret);
- goto err;
- }
-
- dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n",
- __func__, name, supply_list);
- ret = wcd9xxx_dt_parse_vreg_info(dev,
- &pdata->regulator[index + idx],
- name, is_ondemand);
- if (ret)
- goto err;
- }
-
- return 0;
-
-err:
- return ret;
-
-}
-
-/*
- * wcd9xxx_validate_dmic_sample_rate:
- * Given the dmic_sample_rate and mclk rate, validate the
- * dmic_sample_rate. If dmic rate is found to be invalid,
- * assign the dmic rate as undefined, so individual codec
- * drivers can use thier own defaults
- * @dev: the device for which the dmic is to be configured
- * @dmic_sample_rate: The input dmic_sample_rate
- * @mclk_rate: The input codec mclk rate
- * @dmic_rate_type: String to indicate the type of dmic sample
- * rate, used for debug/error logging.
- */
-static u32 wcd9xxx_validate_dmic_sample_rate(struct device *dev,
- u32 dmic_sample_rate, u32 mclk_rate,
- const char *dmic_rate_type)
-{
- u32 div_factor;
-
- if (dmic_sample_rate == WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED ||
- mclk_rate % dmic_sample_rate != 0)
- goto undefined_rate;
-
- div_factor = mclk_rate / dmic_sample_rate;
-
- switch (div_factor) {
- case 2:
- case 3:
- case 4:
- case 16:
- /* Valid dmic DIV factors */
- dev_dbg(dev,
- "%s: DMIC_DIV = %u, mclk_rate = %u\n",
- __func__, div_factor, mclk_rate);
- break;
- case 6:
- /* DIV 6 is valid only for 12.288 MCLK */
- if (mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ)
- goto undefined_rate;
- break;
- default:
- /* Any other DIV factor is invalid */
- goto undefined_rate;
- }
-
- return dmic_sample_rate;
-
-undefined_rate:
- dev_info(dev,
- "%s: Invalid %s = %d, for mclk %d\n",
- __func__,
- dmic_rate_type,
- dmic_sample_rate, mclk_rate);
- dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
- return dmic_sample_rate;
-}
-
-static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
-{
- struct wcd9xxx_pdata *pdata;
- int ret, static_cnt, ond_cnt, cp_supplies_cnt;
- u32 mclk_rate = 0;
- u32 dmic_sample_rate = 0;
- u32 mad_dmic_sample_rate = 0;
- u32 dmic_clk_drive;
- const char *static_prop_name = "qcom,cdc-static-supplies";
- const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
- const char *cp_supplies_name = "qcom,cdc-cp-supplies";
- const char *cdc_name;
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "could not allocate memory for platform data\n");
- return NULL;
- }
-
- static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
- if (IS_ERR_VALUE(static_cnt)) {
- dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
- static_cnt);
- goto err;
- }
-
- /* On-demand supply list is an optional property */
- ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
- if (IS_ERR_VALUE(ond_cnt))
- ond_cnt = 0;
-
- /* cp-supplies list is an optional property */
- cp_supplies_cnt = of_property_count_strings(dev->of_node,
- cp_supplies_name);
- if (IS_ERR_VALUE(cp_supplies_cnt))
- cp_supplies_cnt = 0;
-
- BUG_ON(static_cnt <= 0 || ond_cnt < 0 || cp_supplies_cnt < 0);
- if ((static_cnt + ond_cnt + cp_supplies_cnt)
- > ARRAY_SIZE(pdata->regulator)) {
- dev_err(dev, "%s: Num of supplies %u > max supported %zu\n",
- __func__, static_cnt, ARRAY_SIZE(pdata->regulator));
- goto err;
- }
-
- ret = wcd9xxx_process_supplies(dev, pdata, static_prop_name,
- static_cnt, STATIC_REGULATOR, 0);
- if (ret)
- goto err;
-
- ret = wcd9xxx_process_supplies(dev, pdata, ond_prop_name,
- ond_cnt, ONDEMAND_REGULATOR, static_cnt);
- if (ret)
- goto err;
-
- ret = wcd9xxx_process_supplies(dev, pdata, cp_supplies_name,
- cp_supplies_cnt, ONDEMAND_REGULATOR,
- static_cnt + ond_cnt);
- if (ret)
- goto err;
-
- ret = wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias);
- if (ret)
- goto err;
-
- pdata->wcd_rst_np = of_parse_phandle(dev->of_node,
- "qcom,wcd-rst-gpio-node", 0);
- if (!pdata->wcd_rst_np) {
- pdata->reset_gpio = of_get_named_gpio(dev->of_node,
- "qcom,cdc-reset-gpio", 0);
- if (pdata->reset_gpio < 0) {
- dev_err(dev, "Looking up %s property in node %s failed %d\n",
- "qcom, cdc-reset-gpio",
- dev->of_node->full_name, pdata->reset_gpio);
- goto err;
- }
- dev_dbg(dev, "%s: reset gpio %d", __func__, pdata->reset_gpio);
- }
- ret = of_property_read_u32(dev->of_node,
- "qcom,cdc-mclk-clk-rate",
- &mclk_rate);
- if (ret) {
- dev_err(dev, "Looking up %s property in\n"
- "node %s failed",
- "qcom,cdc-mclk-clk-rate",
- dev->of_node->full_name);
- devm_kfree(dev, pdata);
- ret = -EINVAL;
- goto err;
- }
- pdata->mclk_rate = mclk_rate;
-
- if (pdata->mclk_rate != WCD9XXX_MCLK_CLK_9P6HZ &&
- pdata->mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) {
- dev_err(dev,
- "%s: Invalid mclk_rate = %u\n",
- __func__, pdata->mclk_rate);
- ret = -EINVAL;
- goto err;
- }
-
- ret = of_property_read_u32(dev->of_node,
- "qcom,cdc-dmic-sample-rate",
- &dmic_sample_rate);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed",
- "qcom,cdc-dmic-sample-rate",
- dev->of_node->full_name);
- dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
- }
- pdata->dmic_sample_rate =
- wcd9xxx_validate_dmic_sample_rate(dev,
- dmic_sample_rate,
- pdata->mclk_rate,
- "audio_dmic_rate");
-
- ret = of_property_read_u32(dev->of_node,
- "qcom,cdc-mad-dmic-rate",
- &mad_dmic_sample_rate);
- if (ret) {
- dev_err(dev, "Looking up %s property in node %s failed, err = %d",
- "qcom,cdc-mad-dmic-rate",
- dev->of_node->full_name, ret);
- mad_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
- }
- pdata->mad_dmic_sample_rate =
- wcd9xxx_validate_dmic_sample_rate(dev,
- mad_dmic_sample_rate,
- pdata->mclk_rate,
- "mad_dmic_rate");
-
- pdata->dmic_clk_drv = WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED;
- ret = of_property_read_u32(dev->of_node,
- "qcom,cdc-dmic-clk-drv-strength",
- &dmic_clk_drive);
- if (ret)
- dev_err(dev, "Looking up %s property in node %s failed, err = %d",
- "qcom,cdc-dmic-clk-drv-strength",
- dev->of_node->full_name, ret);
- else if (dmic_clk_drive != 2 && dmic_clk_drive != 4 &&
- dmic_clk_drive != 8 && dmic_clk_drive != 16)
- dev_err(dev, "Invalid cdc-dmic-clk-drv-strength %d\n",
- dmic_clk_drive);
- else
- pdata->dmic_clk_drv = dmic_clk_drive;
-
- ret = of_property_read_string(dev->of_node,
- "qcom,cdc-variant",
- &cdc_name);
- if (ret) {
- dev_dbg(dev, "Property %s not found in node %s\n",
- "qcom,cdc-variant",
- dev->of_node->full_name);
- pdata->cdc_variant = WCD9XXX;
- } else {
- if (!strcmp(cdc_name, "WCD9330"))
- pdata->cdc_variant = WCD9330;
- else
- pdata->cdc_variant = WCD9XXX;
- }
-
- return pdata;
-err:
- devm_kfree(dev, pdata);
- return NULL;
-}
-
static int wcd9xxx_slim_get_laddr(struct slim_device *sb,
const u8 *e_addr, u8 e_len, u8 *laddr)
{
@@ -2860,59 +1209,12 @@ static int wcd9xxx_slim_get_laddr(struct slim_device *sb,
return ret;
}
-static struct regmap_bus regmap_bus_config = {
- .write = regmap_bus_write,
- .gather_write = regmap_bus_gather_write,
- .read = regmap_bus_read,
- .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
- .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
-};
-
-static struct regmap *devm_regmap_init_slim(struct slim_device *slim,
- const struct regmap_config *config)
-{
- return devm_regmap_init(&slim->dev, &regmap_bus_config,
- &slim->dev, config);
-}
-
-static struct regmap *devm_regmap_init_i2c_bus(struct i2c_client *i2c,
- const struct regmap_config *config)
-{
-
- return devm_regmap_init(&i2c->dev, &regmap_bus_config,
- &i2c->dev, config);
-}
-
-static void wcd9xxx_set_codec_specific_param(struct wcd9xxx *wcd9xxx)
-{
- if (!wcd9xxx) {
- pr_err("%s: wcd9xxx is NULL\n", __func__);
- return;
- }
-
- switch (wcd9xxx->type) {
- case WCD9335:
- case WCD9330:
- wcd9xxx->using_regmap = true;
- wcd9xxx->prev_pg_valid = false;
- break;
- default:
- wcd9xxx->using_regmap = false;
- break;
- }
- pr_debug("%s: Codec %s regmap\n",
- __func__, (wcd9xxx->using_regmap ? "using" : "not using"));
-
- return;
-}
-
static int wcd9xxx_slim_probe(struct slim_device *slim)
{
struct wcd9xxx *wcd9xxx;
struct wcd9xxx_pdata *pdata;
int ret = 0;
int intf_type;
- const struct of_device_id *of_id;
intf_type = wcd9xxx_get_intf_type();
@@ -2923,7 +1225,7 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
}
if (slim->dev.of_node) {
dev_info(&slim->dev, "Platform data from device tree\n");
- pdata = wcd9xxx_populate_dt_pdata(&slim->dev);
+ pdata = wcd9xxx_populate_dt_data(&slim->dev);
if (!pdata) {
dev_err(&slim->dev,
"%s: Fail to obtain pdata from device tree\n",
@@ -2953,41 +1255,24 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
goto err;
}
- wcd9xxx = kzalloc(sizeof(struct wcd9xxx), GFP_KERNEL);
- if (wcd9xxx == NULL) {
- pr_err("%s: error, allocation failed\n", __func__);
+ wcd9xxx = devm_kzalloc(&slim->dev, sizeof(struct wcd9xxx),
+ GFP_KERNEL);
+ if (!wcd9xxx) {
ret = -ENOMEM;
goto err;
}
if (!slim->ctrl) {
- pr_err("Error, no SLIMBUS control data\n");
+ dev_err(&slim->dev, "%s: Error, no SLIMBUS control data\n",
+ __func__);
ret = -EINVAL;
goto err_codec;
}
- wcd9xxx->type = WCD9XXX;
- if (slim->dev.of_node) {
- of_id = of_match_device(wcd9xxx_of_match, &slim->dev);
- if (of_id) {
- wcd9xxx->type = *((int *)of_id->data);
- dev_info(&slim->dev, "%s: codec type is %d\n",
- __func__, wcd9xxx->type);
- }
- } else {
- dev_info(&slim->dev, "%s: dev.of_node is NULL, default to WCD9XXX\n",
- __func__);
- wcd9xxx->type = WCD9XXX;
- }
- wcd9xxx_set_codec_specific_param(wcd9xxx);
- if (wcd9xxx->using_regmap) {
- wcd9xxx->regmap = devm_regmap_init_slim(slim,
- &wcd9xxx_base_regmap_config);
- if (IS_ERR(wcd9xxx->regmap)) {
- ret = PTR_ERR(wcd9xxx->regmap);
- dev_err(&slim->dev, "%s: Failed to allocate register map: %d\n",
- __func__, ret);
- goto err_codec;
- }
- }
+ wcd9xxx->type = slim_get_device_id(slim)->driver_data;
+ dev_info(&slim->dev, "%s: probing for wcd type: %d, name: %s\n",
+ __func__, wcd9xxx->type, slim_get_device_id(slim)->name);
+
+ /* wcd9xxx members init */
+ wcd9xxx->multi_reg_write = wcd9xxx_slim_multi_reg_write;
wcd9xxx->slim = slim;
slim_set_clientdata(slim, wcd9xxx);
wcd9xxx->reset_gpio = pdata->reset_gpio;
@@ -2996,28 +1281,43 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
wcd9xxx->dev_up = true;
wcd9xxx->wcd_rst_np = pdata->wcd_rst_np;
+ wcd9xxx->regmap = wcd9xxx_regmap_init(&slim->dev,
+ &wcd9xxx_base_regmap_config);
+ if (IS_ERR(wcd9xxx->regmap)) {
+ ret = PTR_ERR(wcd9xxx->regmap);
+ dev_err(&slim->dev, "%s: Failed to allocate register map: %d\n",
+ __func__, ret);
+ goto err_codec;
+ }
+
if (!wcd9xxx->wcd_rst_np) {
- ret = extcodec_get_pinctrl(&slim->dev);
- if (ret < 0)
- pdata->use_pinctrl = false;
- else
- pdata->use_pinctrl = true;
- } else {
- pdata->use_pinctrl = true;
+ pdata->use_pinctrl = false;
+ dev_err(&slim->dev, "%s: pinctrl not used for rst_n\n",
+ __func__);
+ goto err_codec;
}
- ret = wcd9xxx_init_supplies(wcd9xxx, pdata);
- if (ret) {
- pr_err("%s: Fail to init Codec supplies %d\n", __func__, ret);
+ wcd9xxx->num_of_supplies = pdata->num_supplies;
+ ret = msm_cdc_init_supplies(&slim->dev, &wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
+ if (!wcd9xxx->supplies) {
+ dev_err(wcd9xxx->dev, "%s: Cannot init wcd supplies\n",
+ __func__);
goto err_codec;
}
- ret = wcd9xxx_enable_static_supplies(wcd9xxx, pdata);
+ ret = msm_cdc_enable_static_supplies(wcd9xxx->dev,
+ wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
if (ret) {
- pr_err("%s: Fail to enable Codec pre-reset supplies\n",
- __func__);
+ dev_err(wcd9xxx->dev, "%s: wcd static supply enable failed!\n",
+ __func__);
goto err_codec;
}
- /* For WCD9335, it takes about 600us for the Vout_A and
+
+ /*
+ * For WCD9335, it takes about 600us for the Vout_A and
* Vout_D to be ready after BUCK_SIDO is powered up.
* SYS_RST_N shouldn't be pulled high during this time
*/
@@ -3026,9 +1326,9 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
else
usleep_range(5, 10);
- ret = wcd9xxx_reset(wcd9xxx);
+ ret = wcd9xxx_reset(&slim->dev);
if (ret) {
- pr_err("%s: Resetting Codec failed\n", __func__);
+ dev_err(&slim->dev, "%s: Resetting Codec failed\n", __func__);
goto err_supplies;
}
@@ -3036,7 +1336,7 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
ARRAY_SIZE(wcd9xxx->slim->e_addr),
&wcd9xxx->slim->laddr);
if (ret) {
- pr_err("%s: failed to get slimbus %s logical address: %d\n",
+ dev_err(&slim->dev, "%s: failed to get slimbus %s logical address: %d\n",
__func__, wcd9xxx->slim->name, ret);
ret = -EPROBE_DEFER;
goto err_reset;
@@ -3046,12 +1346,13 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
if (!wcd9xxx->dev->of_node)
- wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+ wcd9xxx_assign_irq(&wcd9xxx->core_res,
pdata->irq, pdata->irq_base);
ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
if (ret) {
- pr_err("%s: error, adding SLIMBUS device failed\n", __func__);
+ dev_err(&slim->dev, "%s: error, adding SLIMBUS device failed\n",
+ __func__);
goto err_reset;
}
@@ -3060,7 +1361,7 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
ARRAY_SIZE(wcd9xxx->slim_slave->e_addr),
&wcd9xxx->slim_slave->laddr);
if (ret) {
- pr_err("%s: failed to get slimbus %s logical address: %d\n",
+ dev_err(&slim->dev, "%s: failed to get slimbus %s logical address: %d\n",
__func__, wcd9xxx->slim->name, ret);
ret = -EPROBE_DEFER;
goto err_slim_add;
@@ -3070,7 +1371,7 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
ret = wcd9xxx_device_init(wcd9xxx);
if (ret) {
- pr_err("%s: error, initializing device failed (%d)\n",
+ dev_err(&slim->dev, "%s: error, initializing device failed (%d)\n",
__func__, ret);
goto err_slim_add;
}
@@ -3103,11 +1404,12 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
err_slim_add:
slim_remove_device(wcd9xxx->slim_slave);
err_reset:
- wcd9xxx_free_reset(wcd9xxx);
+ wcd9xxx_reset_low(wcd9xxx->dev);
err_supplies:
- wcd9xxx_release_supplies(wcd9xxx, pdata);
+ msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
err_codec:
- kfree(wcd9xxx);
slim_set_clientdata(slim, NULL);
err:
return ret;
@@ -3123,7 +1425,9 @@ static int wcd9xxx_slim_remove(struct slim_device *pdev)
wcd9xxx = slim_get_devicedata(pdev);
wcd9xxx_deinit_slimslave(wcd9xxx);
slim_remove_device(wcd9xxx->slim_slave);
- wcd9xxx_release_supplies(wcd9xxx, pdata);
+ msm_cdc_release_supplies(wcd9xxx->dev, wcd9xxx->supplies,
+ pdata->regulator,
+ pdata->num_supplies);
wcd9xxx_device_exit(wcd9xxx);
slim_set_clientdata(pdev, NULL);
return 0;
@@ -3135,7 +1439,7 @@ static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
struct wcd9xxx_core_resource *wcd9xxx_res = &wcd9xxx->core_res;
dev_info(wcd9xxx->dev, "%s: codec bring up\n", __func__);
- wcd9xxx_bring_up(wcd9xxx);
+ wcd9xxx_bringup(wcd9xxx->dev);
ret = wcd9xxx_irq_init(wcd9xxx_res);
if (ret) {
pr_err("%s: wcd9xx_irq_init failed : %d\n", __func__, ret);
@@ -3150,6 +1454,7 @@ static int wcd9xxx_slim_device_reset(struct slim_device *sldev)
{
int ret;
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
if (!wcd9xxx) {
pr_err("%s: wcd9xxx is NULL\n", __func__);
return -EINVAL;
@@ -3160,7 +1465,7 @@ static int wcd9xxx_slim_device_reset(struct slim_device *sldev)
if (wcd9xxx->dev_up)
return 0;
- ret = wcd9xxx_reset(wcd9xxx);
+ ret = wcd9xxx_reset(wcd9xxx->dev);
if (ret)
dev_err(wcd9xxx->dev, "%s: Resetting Codec failed\n", __func__);
@@ -3170,6 +1475,7 @@ static int wcd9xxx_slim_device_reset(struct slim_device *sldev)
static int wcd9xxx_slim_device_up(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
if (!wcd9xxx) {
pr_err("%s: wcd9xxx is NULL\n", __func__);
return -EINVAL;
@@ -3207,6 +1513,7 @@ static int wcd9xxx_slim_device_down(struct slim_device *sldev)
static int wcd9xxx_slim_resume(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
}
@@ -3223,6 +1530,7 @@ static int wcd9xxx_i2c_resume(struct device *dev)
static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
}
@@ -3237,145 +1545,26 @@ static int wcd9xxx_i2c_suspend(struct device *dev)
return 0;
}
-static const struct slim_device_id sitar_slimtest_id[] = {
+static const struct slim_device_id wcd_slim_device_id[] = {
{"sitar-slim", 0},
- {}
-};
-static struct slim_driver sitar_slim_driver = {
- .driver = {
- .name = "sitar-slim",
- .owner = THIS_MODULE,
- },
- .probe = wcd9xxx_slim_probe,
- .remove = wcd9xxx_slim_remove,
- .id_table = sitar_slimtest_id,
- .resume = wcd9xxx_slim_resume,
- .suspend = wcd9xxx_slim_suspend,
-};
-
-static const struct slim_device_id sitar1p1_slimtest_id[] = {
{"sitar1p1-slim", 0},
- {}
-};
-static struct slim_driver sitar1p1_slim_driver = {
- .driver = {
- .name = "sitar1p1-slim",
- .owner = THIS_MODULE,
- },
- .probe = wcd9xxx_slim_probe,
- .remove = wcd9xxx_slim_remove,
- .id_table = sitar1p1_slimtest_id,
- .resume = wcd9xxx_slim_resume,
- .suspend = wcd9xxx_slim_suspend,
-};
-
-static const struct slim_device_id slimtest_id[] = {
{"tabla-slim", 0},
- {}
-};
-
-static struct slim_driver tabla_slim_driver = {
- .driver = {
- .name = "tabla-slim",
- .owner = THIS_MODULE,
- },
- .probe = wcd9xxx_slim_probe,
- .remove = wcd9xxx_slim_remove,
- .id_table = slimtest_id,
- .resume = wcd9xxx_slim_resume,
- .suspend = wcd9xxx_slim_suspend,
-};
-
-static const struct slim_device_id slimtest2x_id[] = {
{"tabla2x-slim", 0},
- {}
-};
-
-static struct slim_driver tabla2x_slim_driver = {
- .driver = {
- .name = "tabla2x-slim",
- .owner = THIS_MODULE,
- },
- .probe = wcd9xxx_slim_probe,
- .remove = wcd9xxx_slim_remove,
- .id_table = slimtest2x_id,
- .resume = wcd9xxx_slim_resume,
- .suspend = wcd9xxx_slim_suspend,
-};
-
-static const struct slim_device_id taiko_slimtest_id[] = {
{"taiko-slim-pgd", 0},
- {}
-};
-
-static struct slim_driver taiko_slim_driver = {
- .driver = {
- .name = "taiko-slim",
- .owner = THIS_MODULE,
- },
- .probe = wcd9xxx_slim_probe,
- .remove = wcd9xxx_slim_remove,
- .id_table = taiko_slimtest_id,
- .resume = wcd9xxx_slim_resume,
- .suspend = wcd9xxx_slim_suspend,
- .device_up = wcd9xxx_slim_device_up,
- .reset_device = wcd9xxx_slim_device_reset,
- .device_down = wcd9xxx_slim_device_down,
-};
-
-static const struct slim_device_id tapan_slimtest_id[] = {
{"tapan-slim-pgd", 0},
+ {"tomtom-slim-pgd", WCD9330},
+ {"tasha-slim-pgd", WCD9335},
{}
};
-static struct slim_driver tapan_slim_driver = {
+static struct slim_driver wcd_slim_driver = {
.driver = {
- .name = "tapan-slim",
+ .name = "wcd-slim",
.owner = THIS_MODULE,
},
.probe = wcd9xxx_slim_probe,
.remove = wcd9xxx_slim_remove,
- .id_table = tapan_slimtest_id,
- .resume = wcd9xxx_slim_resume,
- .suspend = wcd9xxx_slim_suspend,
- .device_up = wcd9xxx_slim_device_up,
- .reset_device = wcd9xxx_slim_device_reset,
- .device_down = wcd9xxx_slim_device_down,
-};
-
-static const struct slim_device_id tomtom_slimtest_id[] = {
- {"tomtom-slim-pgd", 0},
- {}
-};
-
-static const struct slim_device_id tasha_slimtest_id[] = {
- {"tasha-slim-pgd", 0},
- {}
-};
-
-static struct slim_driver tomtom_slim_driver = {
- .driver = {
- .name = "tomtom-slim",
- .owner = THIS_MODULE,
- },
- .probe = wcd9xxx_slim_probe,
- .remove = wcd9xxx_slim_remove,
- .id_table = tomtom_slimtest_id,
- .resume = wcd9xxx_slim_resume,
- .suspend = wcd9xxx_slim_suspend,
- .device_up = wcd9xxx_slim_device_up,
- .reset_device = wcd9xxx_slim_device_reset,
- .device_down = wcd9xxx_slim_device_down,
-};
-
-static struct slim_driver wcd9335_slim_driver = {
- .driver = {
- .name = "wcd9335-slim",
- .owner = THIS_MODULE,
- },
- .probe = wcd9xxx_slim_probe,
- .remove = wcd9xxx_slim_remove,
- .id_table = tasha_slimtest_id,
+ .id_table = wcd_slim_device_id,
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
.device_up = wcd9xxx_slim_device_up,
@@ -3445,61 +1634,36 @@ static struct i2c_driver wcd9335_i2c_driver = {
static int __init wcd9xxx_init(void)
{
- int ret[NUM_WCD9XXX_REG_RET];
+ int ret[NUM_WCD9XXX_REG_RET] = {0};
int i = 0;
wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
- ret[0] = slim_driver_register(&tabla_slim_driver);
+ ret[0] = i2c_add_driver(&tabla_i2c_driver);
if (ret[0])
- pr_err("Failed to register tabla SB driver: %d\n", ret[0]);
+ pr_err("%s: Failed to add the tabla2x I2C driver: %d\n",
+ __func__, ret[0]);
- ret[1] = slim_driver_register(&tabla2x_slim_driver);
+ ret[1] = i2c_add_driver(&wcd9xxx_i2c_driver);
if (ret[1])
- pr_err("Failed to register tabla2x SB driver: %d\n", ret[1]);
+ pr_err("%s: Failed to add the wcd9xxx I2C driver: %d\n",
+ __func__, ret[1]);
- ret[2] = i2c_add_driver(&tabla_i2c_driver);
+ ret[2] = i2c_add_driver(&wcd9335_i2c_driver);
if (ret[2])
- pr_err("failed to add the tabla2x I2C driver: %d\n", ret[2]);
+ pr_err("%s: Failed to add the wcd9335 I2C driver: %d\n",
+ __func__, ret[2]);
- ret[3] = slim_driver_register(&sitar_slim_driver);
+ ret[3] = slim_driver_register(&wcd_slim_driver);
if (ret[3])
- pr_err("Failed to register sitar SB driver: %d\n", ret[3]);
-
- ret[4] = slim_driver_register(&sitar1p1_slim_driver);
- if (ret[4])
- pr_err("Failed to register sitar SB driver: %d\n", ret[4]);
-
- ret[5] = slim_driver_register(&taiko_slim_driver);
- if (ret[5])
- pr_err("Failed to register taiko SB driver: %d\n", ret[5]);
-
- ret[6] = i2c_add_driver(&wcd9xxx_i2c_driver);
- if (ret[6])
- pr_err("failed to add the wcd9xxx I2C driver: %d\n", ret[6]);
-
- ret[7] = slim_driver_register(&tapan_slim_driver);
- if (ret[7])
- pr_err("Failed to register tapan SB driver: %d\n", ret[7]);
-
- ret[8] = slim_driver_register(&tomtom_slim_driver);
- if (ret[8])
- pr_err("Failed to register tomtom SB driver: %d\n", ret[8]);
-
- ret[9] = slim_driver_register(&wcd9335_slim_driver);
- if (ret[9])
- pr_err("Failed to register tomtom SB driver: %d\n", ret[9]);
-
-
- ret[10] = i2c_add_driver(&wcd9335_i2c_driver);
- if (ret[10])
- pr_err("failed to add the wcd9335 I2C driver: %d\n", ret[10]);
-
+ pr_err("%s: Failed to register wcd SB driver: %d\n",
+ __func__, ret[3]);
for (i = 0; i < NUM_WCD9XXX_REG_RET; i++) {
if (ret[i])
return ret[i];
}
+
return 0;
}
module_init(wcd9xxx_init);
@@ -3507,6 +1671,11 @@ module_init(wcd9xxx_init);
static void __exit wcd9xxx_exit(void)
{
wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
+
+ i2c_del_driver(&tabla_i2c_driver);
+ i2c_del_driver(&wcd9xxx_i2c_driver);
+ i2c_del_driver(&wcd9335_i2c_driver);
+ slim_driver_unregister(&wcd_slim_driver);
}
module_exit(wcd9xxx_exit);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index a171950fe72e..8024fab80295 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -15,8 +15,10 @@
#include <linux/sched.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
+#include <linux/regmap.h>
+#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
#include <linux/delay.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
@@ -75,9 +77,9 @@ static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
pr_err("%s: Array Size out of bound\n", __func__);
return;
}
- if (!wcd9xxx_res->codec_reg_write) {
- pr_err("%s: Codec reg write callback function not defined\n",
- __func__);
+ if (!wcd9xxx_res->wcd_core_regmap) {
+ pr_err("%s: Codec core regmap not defined\n",
+ __func__);
return;
}
@@ -90,7 +92,7 @@ static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
wcd9xxx_res->irq_masks_cache[i] =
wcd9xxx_res->irq_masks_cur[i];
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i,
wcd9xxx_res->irq_masks_cur[i]);
}
@@ -244,21 +246,21 @@ static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res,
struct intr_data *irqdata)
{
int irqbit = irqdata->intr_num;
- if (!wcd9xxx_res->codec_reg_write) {
- pr_err("%s: codec read/write callback not defined\n",
- __func__);
+ if (!wcd9xxx_res->wcd_core_regmap) {
+ pr_err("%s: codec core regmap not defined\n",
+ __func__);
return;
}
if (irqdata->clear_first) {
wcd9xxx_nested_irq_lock(wcd9xxx_res);
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] +
BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
0x02);
handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
@@ -266,12 +268,12 @@ static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res,
} else {
wcd9xxx_nested_irq_lock(wcd9xxx_res);
handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] +
BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
0x02);
@@ -295,16 +297,16 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
return IRQ_NONE;
}
- if (!wcd9xxx_res->codec_bulk_read) {
+ if (!wcd9xxx_res->wcd_core_regmap) {
dev_err(wcd9xxx_res->dev,
- "%s: Codec Bulk Register read callback not supplied\n",
+ "%s: Codec core regmap not supplied\n",
__func__);
goto err_disable_irq;
}
- ret = wcd9xxx_res->codec_bulk_read(wcd9xxx_res,
+ ret = regmap_bulk_read(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_STATUS_BASE],
- num_irq_regs, status);
+ status, num_irq_regs);
if (ret < 0) {
dev_err(wcd9xxx_res->dev,
@@ -358,11 +360,11 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
memset(status, 0xff, num_irq_regs);
- ret = wcd9xxx_res->codec_bulk_write(wcd9xxx_res,
+ ret = regmap_bulk_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE],
- num_irq_regs, status);
+ status, num_irq_regs);
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
0x02);
}
@@ -480,9 +482,9 @@ int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
wcd9xxx_res->irq_level_high[i] << (i % BITS_PER_BYTE);
}
- if (!wcd9xxx_res->codec_reg_write) {
+ if (!wcd9xxx_res->wcd_core_regmap) {
dev_err(wcd9xxx_res->dev,
- "%s: Codec Register write callback not defined\n",
+ "%s: Codec core regmap not defined\n",
__func__);
ret = -EINVAL;
goto fail_irq_init;
@@ -490,10 +492,10 @@ int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
for (i = 0; i < wcd9xxx_res->num_irq_regs; i++) {
/* Initialize interrupt mask and level registers */
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] + i,
irq_level[i]);
- wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i,
wcd9xxx_res->irq_masks_cur[i]);
}
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 30fd0dedd609..c63e8d6d926e 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. 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 and
@@ -32,7 +32,7 @@ static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
{
if (wcd9xxx->codec_type->slim_slave_type ==
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA) {
+ WCD9XXX_SLIM_SLAVE_ADDR_TYPE_0) {
sh_ch.rx_port_ch_reg_base = 0x180;
sh_ch.port_rx_cfg_reg_base = 0x040;
sh_ch.port_tx_cfg_reg_base = 0x040;
diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c
new file mode 100644
index 000000000000..6bfe3d5a1788
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-utils.c
@@ -0,0 +1,1147 @@
+/* Copyright (c) 2016, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
+#include <linux/mfd/msm-cdc-supply.h>
+#include <linux/mfd/msm-cdc-pinctrl.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-utils.h>
+
+#define REG_BYTES 2
+#define VAL_BYTES 1
+/*
+ * Page Register Address that APP Proc uses to
+ * access WCD9335 Codec registers is identified
+ * as 0x00
+ */
+#define PAGE_REG_ADDR 0x00
+
+static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
+
+static struct mfd_cell tasha_devs[] = {
+ {
+ .name = "tasha_codec",
+ },
+};
+
+static struct mfd_cell tomtom_devs[] = {
+ {
+ .name = "tomtom_codec",
+ },
+};
+
+static int wcd9xxx_read_of_property_u32(struct device *dev, const char *name,
+ u32 *val)
+{
+ int rc = 0;
+
+ rc = of_property_read_u32(dev->of_node, name, val);
+ if (rc)
+ dev_err(dev, "%s: Looking up %s property in node %s failed",
+ __func__, name, dev->of_node->full_name);
+
+ return rc;
+}
+
+static void wcd9xxx_dt_parse_micbias_info(struct device *dev,
+ struct wcd9xxx_micbias_setting *mb)
+{
+ u32 prop_val;
+ int rc;
+
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias-ldoh-v", NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias-ldoh-v",
+ &prop_val);
+ if (!rc)
+ mb->ldoh_v = (u8)prop_val;
+ }
+
+ /* MB1 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt1-mv",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias-cfilt1-mv",
+ &prop_val);
+ if (!rc)
+ mb->cfilt1_mv = prop_val;
+
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias1-cfilt-sel",
+ &prop_val);
+ if (!rc)
+ mb->bias1_cfilt_sel = (u8)prop_val;
+
+ } else if (of_find_property(dev->of_node, "qcom,cdc-micbias1-mv",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias1-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb1_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias1 DT property not found\n",
+ __func__);
+ }
+
+ /* MB2 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt2-mv",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias-cfilt2-mv",
+ &prop_val);
+ if (!rc)
+ mb->cfilt2_mv = prop_val;
+
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias2-cfilt-sel",
+ &prop_val);
+ if (!rc)
+ mb->bias2_cfilt_sel = (u8)prop_val;
+
+ } else if (of_find_property(dev->of_node, "qcom,cdc-micbias2-mv",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias2-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb2_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias2 DT property not found\n",
+ __func__);
+ }
+
+ /* MB3 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias-cfilt3-mv",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias-cfilt3-mv",
+ &prop_val);
+ if (!rc)
+ mb->cfilt3_mv = prop_val;
+
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias3-cfilt-sel",
+ &prop_val);
+ if (!rc)
+ mb->bias3_cfilt_sel = (u8)prop_val;
+
+ } else if (of_find_property(dev->of_node, "qcom,cdc-micbias3-mv",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias3-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb3_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias3 DT property not found\n",
+ __func__);
+ }
+
+ /* MB4 */
+ if (of_find_property(dev->of_node, "qcom,cdc-micbias4-cfilt-sel",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias4-cfilt-sel",
+ &prop_val);
+ if (!rc)
+ mb->bias4_cfilt_sel = (u8)prop_val;
+
+ } else if (of_find_property(dev->of_node, "qcom,cdc-micbias4-mv",
+ NULL)) {
+ rc = wcd9xxx_read_of_property_u32(dev,
+ "qcom,cdc-micbias4-mv",
+ &prop_val);
+ if (!rc)
+ mb->micb4_mv = prop_val;
+ } else {
+ dev_info(dev, "%s: Micbias4 DT property not found\n",
+ __func__);
+ }
+
+ mb->bias1_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ mb->bias2_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias2-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ mb->bias3_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias3-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+ mb->bias4_cap_mode =
+ (of_property_read_bool(dev->of_node, "qcom,cdc-micbias4-ext-cap") ?
+ MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
+
+ mb->bias2_is_headset_only =
+ of_property_read_bool(dev->of_node,
+ "qcom,cdc-micbias2-headset-only");
+
+ /* Print micbias info */
+ dev_dbg(dev, "%s: ldoh_v %u cfilt1_mv %u cfilt2_mv %u cfilt3_mv %u",
+ __func__, (u32)mb->ldoh_v, (u32)mb->cfilt1_mv,
+ (u32)mb->cfilt2_mv, (u32)mb->cfilt3_mv);
+
+ dev_dbg(dev, "%s: micb1_mv %u micb2_mv %u micb3_mv %u micb4_mv %u",
+ __func__, mb->micb1_mv, mb->micb2_mv,
+ mb->micb3_mv, mb->micb4_mv);
+
+ dev_dbg(dev, "%s: bias1_cfilt_sel %u bias2_cfilt_sel %u\n",
+ __func__, (u32)mb->bias1_cfilt_sel, (u32)mb->bias2_cfilt_sel);
+
+ dev_dbg(dev, "%s: bias3_cfilt_sel %u bias4_cfilt_sel %u\n",
+ __func__, (u32)mb->bias3_cfilt_sel, (u32)mb->bias4_cfilt_sel);
+
+ dev_dbg(dev, "%s: bias1_ext_cap %d bias2_ext_cap %d\n",
+ __func__, mb->bias1_cap_mode, mb->bias2_cap_mode);
+
+ dev_dbg(dev, "%s: bias3_ext_cap %d bias4_ext_cap %d\n",
+ __func__, mb->bias3_cap_mode, mb->bias4_cap_mode);
+
+ dev_dbg(dev, "%s: bias2_is_headset_only %d\n",
+ __func__, mb->bias2_is_headset_only);
+}
+
+/*
+ * wcd9xxx_validate_dmic_sample_rate:
+ * Given the dmic_sample_rate and mclk rate, validate the
+ * dmic_sample_rate. If dmic rate is found to be invalid,
+ * assign the dmic rate as undefined, so individual codec
+ * drivers can use their own defaults
+ * @dev: the device for which the dmic is to be configured
+ * @dmic_sample_rate: The input dmic_sample_rate
+ * @mclk_rate: The input codec mclk rate
+ * @dmic_rate_type: String to indicate the type of dmic sample
+ * rate, used for debug/error logging.
+ */
+static u32 wcd9xxx_validate_dmic_sample_rate(struct device *dev,
+ u32 dmic_sample_rate, u32 mclk_rate,
+ const char *dmic_rate_type)
+{
+ u32 div_factor;
+
+ if (dmic_sample_rate == WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED ||
+ mclk_rate % dmic_sample_rate != 0)
+ goto undefined_rate;
+
+ div_factor = mclk_rate / dmic_sample_rate;
+
+ switch (div_factor) {
+ case 2:
+ case 3:
+ case 4:
+ case 8:
+ case 16:
+ /* Valid dmic DIV factors */
+ dev_dbg(dev, "%s: DMIC_DIV = %u, mclk_rate = %u\n",
+ __func__, div_factor, mclk_rate);
+ break;
+ case 6:
+ /* DIV 6 is valid only for 12.288 MCLK */
+ if (mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ)
+ goto undefined_rate;
+ break;
+ default:
+ /* Any other DIV factor is invalid */
+ goto undefined_rate;
+ }
+
+ return dmic_sample_rate;
+
+undefined_rate:
+ dev_info(dev, "%s: Invalid %s = %d, for mclk %d\n",
+ __func__, dmic_rate_type, dmic_sample_rate, mclk_rate);
+ dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
+
+ return dmic_sample_rate;
+}
+
+/*
+ * wcd9xxx_populate_dt_data:
+ * Parse device tree properties for the given codec device
+ *
+ * @dev: pointer to codec device
+ *
+ * Returns pointer to the platform data resulting from parsing
+ * device tree.
+ */
+struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev)
+{
+ struct wcd9xxx_pdata *pdata;
+ u32 dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
+ u32 mad_dmic_sample_rate = WCD9XXX_DMIC_SAMPLE_RATE_UNDEFINED;
+ u32 dmic_clk_drive = WCD9XXX_DMIC_CLK_DRIVE_UNDEFINED;
+ u32 prop_val;
+
+ if (!dev || !dev->of_node)
+ return NULL;
+
+ pdata = devm_kzalloc(dev, sizeof(struct wcd9xxx_pdata),
+ GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ /* Parse power supplies */
+ msm_cdc_get_power_supplies(dev, &pdata->regulator,
+ &pdata->num_supplies);
+ if (!pdata->regulator || (pdata->num_supplies <= 0)) {
+ dev_err(dev, "%s: no power supplies defined for codec\n",
+ __func__);
+ goto err_power_sup;
+ }
+
+ /* Parse micbias info */
+ wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias);
+
+ pdata->wcd_rst_np = of_parse_phandle(dev->of_node,
+ "qcom,wcd-rst-gpio-node", 0);
+ if (!pdata->wcd_rst_np) {
+ dev_err(dev, "%s: Looking up %s property in node %s failed\n",
+ __func__, "qcom,wcd-rst-gpio-node",
+ dev->of_node->full_name);
+ goto err_parse_dt_prop;
+ }
+
+ if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-mclk-clk-rate",
+ &prop_val)))
+ pdata->mclk_rate = prop_val;
+
+ if (pdata->mclk_rate != WCD9XXX_MCLK_CLK_9P6HZ &&
+ pdata->mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) {
+ dev_err(dev, "%s: Invalid mclk_rate = %u\n", __func__,
+ pdata->mclk_rate);
+ goto err_parse_dt_prop;
+ }
+
+ if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-dmic-sample-rate",
+ &prop_val)))
+ dmic_sample_rate = prop_val;
+
+ pdata->dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev,
+ dmic_sample_rate,
+ pdata->mclk_rate,
+ "audio_dmic_rate");
+ if (!(wcd9xxx_read_of_property_u32(dev, "qcom,cdc-mad-dmic-rate",
+ &prop_val)))
+ mad_dmic_sample_rate = prop_val;
+
+ pdata->mad_dmic_sample_rate = wcd9xxx_validate_dmic_sample_rate(dev,
+ mad_dmic_sample_rate,
+ pdata->mclk_rate,
+ "mad_dmic_rate");
+
+ if (!(of_property_read_u32(dev->of_node,
+ "qcom,cdc-dmic-clk-drv-strength",
+ &prop_val)))
+ dmic_clk_drive = prop_val;
+
+ if (dmic_clk_drive != 2 && dmic_clk_drive != 4 &&
+ dmic_clk_drive != 8 && dmic_clk_drive != 16)
+ dev_err(dev, "Invalid cdc-dmic-clk-drv-strength %d\n",
+ dmic_clk_drive);
+
+ pdata->dmic_clk_drv = dmic_clk_drive;
+
+ return pdata;
+
+err_parse_dt_prop:
+ devm_kfree(dev, pdata->regulator);
+ pdata->regulator = NULL;
+ pdata->num_supplies = 0;
+err_power_sup:
+ devm_kfree(dev, pdata);
+ return NULL;
+}
+EXPORT_SYMBOL(wcd9xxx_populate_dt_data);
+
+static bool is_wcd9xxx_reg_power_down(struct wcd9xxx *wcd9xxx, u16 rreg)
+{
+ bool ret = false;
+ int i;
+ struct wcd9xxx_power_region *wcd9xxx_pwr;
+
+ if (!wcd9xxx)
+ return ret;
+
+ for (i = 0; i < WCD9XXX_MAX_PWR_REGIONS; i++) {
+ wcd9xxx_pwr = wcd9xxx->wcd9xxx_pwr[i];
+ if (!wcd9xxx_pwr)
+ continue;
+ if (((wcd9xxx_pwr->pwr_collapse_reg_min == 0) &&
+ (wcd9xxx_pwr->pwr_collapse_reg_max == 0)) ||
+ (wcd9xxx_pwr->power_state ==
+ WCD_REGION_POWER_COLLAPSE_REMOVE))
+ ret = false;
+ else if (((wcd9xxx_pwr->power_state ==
+ WCD_REGION_POWER_DOWN) ||
+ (wcd9xxx_pwr->power_state ==
+ WCD_REGION_POWER_COLLAPSE_BEGIN)) &&
+ (rreg >= wcd9xxx_pwr->pwr_collapse_reg_min) &&
+ (rreg <= wcd9xxx_pwr->pwr_collapse_reg_max))
+ ret = true;
+ }
+ return ret;
+}
+
+/*
+ * wcd9xxx_page_write:
+ * Retrieve page number from register and
+ * write that page number to the page address.
+ * Called under io_lock acquisition.
+ *
+ * @wcd9xxx: pointer to wcd9xxx
+ * @reg: Register address from which page number is retrieved
+ *
+ * Returns 0 for success and negative error code for failure.
+ */
+int wcd9xxx_page_write(struct wcd9xxx *wcd9xxx, unsigned short *reg)
+{
+ int ret = 0;
+ unsigned short c_reg, reg_addr;
+ u8 pg_num, prev_pg_num;
+
+ if (wcd9xxx->type != WCD9335)
+ return ret;
+
+ c_reg = *reg;
+ pg_num = c_reg >> 8;
+ reg_addr = c_reg & 0xff;
+ if (wcd9xxx->prev_pg_valid) {
+ prev_pg_num = wcd9xxx->prev_pg;
+ if (prev_pg_num != pg_num) {
+ ret = wcd9xxx->write_dev(
+ wcd9xxx, PAGE_REG_ADDR, 1,
+ (void *) &pg_num, false);
+ if (ret < 0)
+ pr_err("page write error, pg_num: 0x%x\n",
+ pg_num);
+ else {
+ wcd9xxx->prev_pg = pg_num;
+ dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n",
+ __func__, pg_num);
+ }
+ }
+ } else {
+ ret = wcd9xxx->write_dev(
+ wcd9xxx, PAGE_REG_ADDR, 1, (void *) &pg_num,
+ false);
+ if (ret < 0)
+ pr_err("page write error, pg_num: 0x%x\n", pg_num);
+ else {
+ wcd9xxx->prev_pg = pg_num;
+ wcd9xxx->prev_pg_valid = true;
+ dev_dbg(wcd9xxx->dev, "%s: Page 0x%x Write to 0x00\n",
+ __func__, pg_num);
+ }
+ }
+ *reg = reg_addr;
+ return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_page_write);
+
+static int regmap_bus_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct device *dev = context;
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+ unsigned short c_reg, rreg;
+ int ret, i;
+
+ if (!wcd9xxx) {
+ dev_err(dev, "%s: wcd9xxx is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (!reg || !val) {
+ dev_err(dev, "%s: reg or val is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (reg_size != REG_BYTES) {
+ dev_err(dev, "%s: register size %zd bytes, not supported\n",
+ __func__, reg_size);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wcd9xxx->io_lock);
+ c_reg = *(u16 *)reg;
+ rreg = c_reg;
+
+ if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) {
+ ret = 0;
+ for (i = 0; i < val_size; i++)
+ ((u8 *)val)[i] = 0;
+ goto err;
+ }
+ ret = wcd9xxx_page_write(wcd9xxx, &c_reg);
+ if (ret)
+ goto err;
+ ret = wcd9xxx->read_dev(wcd9xxx, c_reg, val_size, val, false);
+ if (ret < 0)
+ dev_err(dev, "%s: Codec read failed (%d), reg: 0x%x, size:%zd\n",
+ __func__, ret, rreg, val_size);
+ else {
+ for (i = 0; i < val_size; i++)
+ dev_dbg(dev, "%s: Read 0x%02x from 0x%x\n",
+ __func__, ((u8 *)val)[i], rreg + i);
+ }
+err:
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ return ret;
+}
+
+static int regmap_bus_gather_write(void *context,
+ const void *reg, size_t reg_size,
+ const void *val, size_t val_size)
+{
+ struct device *dev = context;
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+ unsigned short c_reg, rreg;
+ int ret, i;
+
+ if (!wcd9xxx) {
+ dev_err(dev, "%s: wcd9xxx is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (!reg || !val) {
+ dev_err(dev, "%s: reg or val is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (reg_size != REG_BYTES) {
+ dev_err(dev, "%s: register size %zd bytes, not supported\n",
+ __func__, reg_size);
+ return -EINVAL;
+ }
+ mutex_lock(&wcd9xxx->io_lock);
+ c_reg = *(u16 *)reg;
+ rreg = c_reg;
+
+ if (is_wcd9xxx_reg_power_down(wcd9xxx, rreg)) {
+ ret = 0;
+ goto err;
+ }
+ ret = wcd9xxx_page_write(wcd9xxx, &c_reg);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < val_size; i++)
+ dev_dbg(dev, "Write %02x to 0x%x\n", ((u8 *)val)[i],
+ rreg + i);
+
+ ret = wcd9xxx->write_dev(wcd9xxx, c_reg, val_size, (void *) val,
+ false);
+ if (ret < 0)
+ dev_err(dev, "%s: Codec write failed (%d), reg:0x%x, size:%zd\n",
+ __func__, ret, rreg, val_size);
+
+err:
+ mutex_unlock(&wcd9xxx->io_lock);
+ return ret;
+}
+
+static int regmap_bus_write(void *context, const void *data, size_t count)
+{
+ struct device *dev = context;
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(dev);
+
+ if (!wcd9xxx)
+ return -EINVAL;
+
+ WARN_ON(count < REG_BYTES);
+
+ if (count > (REG_BYTES + VAL_BYTES)) {
+ if (wcd9xxx->multi_reg_write)
+ return wcd9xxx->multi_reg_write(wcd9xxx,
+ data, count);
+ } else
+ return regmap_bus_gather_write(context, data, REG_BYTES,
+ data + REG_BYTES,
+ count - REG_BYTES);
+
+ dev_err(dev, "%s: bus multi reg write failure\n", __func__);
+
+ return -EINVAL;
+}
+
+static struct regmap_bus regmap_bus_config = {
+ .write = regmap_bus_write,
+ .gather_write = regmap_bus_gather_write,
+ .read = regmap_bus_read,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/*
+ * wcd9xxx_regmap_init:
+ * Initialize wcd9xxx register map
+ *
+ * @dev: pointer to wcd device
+ * @config: pointer to register map config
+ *
+ * Returns pointer to regmap structure for success
+ * or NULL in case of failure.
+ */
+struct regmap *wcd9xxx_regmap_init(struct device *dev,
+ const struct regmap_config *config)
+{
+ return devm_regmap_init(dev, &regmap_bus_config, dev, config);
+}
+EXPORT_SYMBOL(wcd9xxx_regmap_init);
+
+/*
+ * wcd9xxx_reset:
+ * Reset wcd9xxx codec
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_reset(struct device *dev)
+{
+ struct wcd9xxx *wcd9xxx;
+ int rc;
+
+ if (!dev)
+ return -ENODEV;
+
+ wcd9xxx = dev_get_drvdata(dev);
+ if (!wcd9xxx)
+ return -EINVAL;
+
+ if (!wcd9xxx->wcd_rst_np) {
+ dev_err(dev, "%s: reset gpio device node not specified\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np);
+ if (rc) {
+ dev_err(dev, "%s: wcd sleep state request fail!\n",
+ __func__);
+ return rc;
+ }
+
+ /* 20ms sleep required after pulling the reset gpio to LOW */
+ msleep(20);
+
+ rc = msm_cdc_pinctrl_select_active_state(wcd9xxx->wcd_rst_np);
+ if (rc) {
+ dev_err(dev, "%s: wcd active state request fail!\n",
+ __func__);
+ return rc;
+ }
+ msleep(20);
+
+ return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_reset);
+
+/*
+ * wcd9xxx_reset_low:
+ * Pull the wcd9xxx codec reset_n to low
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_reset_low(struct device *dev)
+{
+ struct wcd9xxx *wcd9xxx;
+ int rc;
+
+ if (!dev)
+ return -ENODEV;
+
+ wcd9xxx = dev_get_drvdata(dev);
+ if (!wcd9xxx)
+ return -EINVAL;
+
+ if (!wcd9xxx->wcd_rst_np) {
+ dev_err(dev, "%s: reset gpio device node not specified\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np);
+ if (rc)
+ dev_err(dev, "%s: wcd sleep state request fail!\n",
+ __func__);
+
+ return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_reset_low);
+
+/*
+ * wcd9xxx_bringup:
+ * Toggle reset analog and digital cores of wcd9xxx codec
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_bringup(struct device *dev)
+{
+ struct wcd9xxx *wcd9xxx;
+ int rc;
+ codec_bringup_fn cdc_bup_fn;
+
+ if (!dev)
+ return -ENODEV;
+
+ wcd9xxx = dev_get_drvdata(dev);
+ if (!wcd9xxx)
+ return -EINVAL;
+
+ cdc_bup_fn = wcd9xxx_bringup_fn(wcd9xxx->type);
+ if (!cdc_bup_fn) {
+ dev_err(dev, "%s: Codec bringup fn NULL!\n",
+ __func__);
+ return -EINVAL;
+ }
+ rc = cdc_bup_fn(wcd9xxx);
+ if (rc)
+ dev_err(dev, "%s: Codec bringup error, rc: %d\n",
+ __func__, rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_bringup);
+
+/*
+ * wcd9xxx_bringup:
+ * Set analog and digital cores of wcd9xxx codec in reset state
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_bringdown(struct device *dev)
+{
+ struct wcd9xxx *wcd9xxx;
+ int rc;
+ codec_bringdown_fn cdc_bdown_fn;
+
+ if (!dev)
+ return -ENODEV;
+
+ wcd9xxx = dev_get_drvdata(dev);
+ if (!wcd9xxx)
+ return -EINVAL;
+
+ cdc_bdown_fn = wcd9xxx_bringdown_fn(wcd9xxx->type);
+ if (!cdc_bdown_fn) {
+ dev_err(dev, "%s: Codec bring down fn NULL!\n",
+ __func__);
+ return -EINVAL;
+ }
+ rc = cdc_bdown_fn(wcd9xxx);
+ if (rc)
+ dev_err(dev, "%s: Codec bring down error, rc: %d\n",
+ __func__, rc);
+
+ return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_bringdown);
+
+/*
+ * wcd9xxx_get_codec_info:
+ * Fill codec specific information like interrupts, version
+ *
+ * @dev: pointer to wcd device
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_get_codec_info(struct device *dev)
+{
+ struct wcd9xxx *wcd9xxx;
+ int rc;
+ codec_type_fn cdc_type_fn;
+ struct wcd9xxx_codec_type *cinfo;
+
+ if (!dev)
+ return -ENODEV;
+
+ wcd9xxx = dev_get_drvdata(dev);
+ if (!wcd9xxx)
+ return -EINVAL;
+
+ cdc_type_fn = wcd9xxx_get_codec_info_fn(wcd9xxx->type);
+ if (!cdc_type_fn) {
+ dev_err(dev, "%s: Codec fill type fn NULL!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ cinfo = wcd9xxx->codec_type;
+ if (!cinfo)
+ return -EINVAL;
+
+ rc = cdc_type_fn(wcd9xxx, cinfo);
+ if (rc) {
+ dev_err(dev, "%s: Codec type fill failed, rc:%d\n",
+ __func__, rc);
+ return rc;
+
+ }
+
+ switch (wcd9xxx->type) {
+ case WCD9335:
+ cinfo->dev = tasha_devs;
+ cinfo->size = ARRAY_SIZE(tasha_devs);
+ break;
+ case WCD9330:
+ cinfo->dev = tomtom_devs;
+ cinfo->size = ARRAY_SIZE(tomtom_devs);
+ break;
+ default:
+ cinfo->dev = NULL;
+ cinfo->size = 0;
+ break;
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL(wcd9xxx_get_codec_info);
+
+/*
+ * wcd9xxx_core_irq_init:
+ * Initialize wcd9xxx codec irq instance
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_core_irq_init(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+ int ret = 0;
+
+ if (!wcd9xxx_core_res)
+ return -EINVAL;
+
+ if (wcd9xxx_core_res->irq != 1) {
+ ret = wcd9xxx_irq_init(wcd9xxx_core_res);
+ if (ret)
+ pr_err("IRQ initialization failed\n");
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_irq_init);
+
+/*
+ * wcd9xxx_assign_irq:
+ * Assign irq and irq_base to wcd9xxx core resource
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @irq: irq number
+ * @irq_base: base irq number
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_assign_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ unsigned int irq,
+ unsigned int irq_base)
+{
+ if (!wcd9xxx_core_res)
+ return -EINVAL;
+
+ wcd9xxx_core_res->irq = irq;
+ wcd9xxx_core_res->irq_base = irq_base;
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_assign_irq);
+
+/*
+ * wcd9xxx_core_res_init:
+ * Initialize wcd core resource instance
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @num_irqs: number of irqs for wcd9xxx core
+ * @num_irq_regs: number of irq registers
+ * @wcd_regmap: pointer to the wcd register map
+ *
+ * Returns 0 for success or negative error code in case of failure
+ */
+int wcd9xxx_core_res_init(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ int num_irqs, int num_irq_regs, struct regmap *wcd_regmap)
+{
+ if (!wcd9xxx_core_res || !wcd_regmap)
+ return -EINVAL;
+
+ mutex_init(&wcd9xxx_core_res->pm_lock);
+ wcd9xxx_core_res->wlock_holders = 0;
+ wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+ init_waitqueue_head(&wcd9xxx_core_res->pm_wq);
+ pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
+ wcd9xxx_core_res->num_irqs = num_irqs;
+ wcd9xxx_core_res->num_irq_regs = num_irq_regs;
+ wcd9xxx_core_res->wcd_core_regmap = wcd_regmap;
+
+ pr_info("%s: num_irqs = %d, num_irq_regs = %d\n",
+ __func__, wcd9xxx_core_res->num_irqs,
+ wcd9xxx_core_res->num_irq_regs);
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_init);
+
+/*
+ * wcd9xxx_core_res_deinit:
+ * Deinit wcd core resource instance
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ */
+void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+ if (!wcd9xxx_core_res)
+ return;
+
+ pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req);
+ mutex_destroy(&wcd9xxx_core_res->pm_lock);
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_deinit);
+
+/*
+ * wcd9xxx_pm_cmpxchg:
+ * Check old state and exchange with pm new state
+ * if old state matches with current state
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @o: pm old state
+ * @n: pm new state
+ *
+ * Returns old state
+ */
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ enum wcd9xxx_pm_state o,
+ enum wcd9xxx_pm_state n)
+{
+ enum wcd9xxx_pm_state old;
+
+ if (!wcd9xxx_core_res)
+ return o;
+
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ old = wcd9xxx_core_res->pm_state;
+ if (old == o)
+ wcd9xxx_core_res->pm_state = n;
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+
+ return old;
+}
+EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg);
+
+/*
+ * wcd9xxx_core_res_suspend:
+ * Suspend callback function for wcd9xxx core
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ * @pm_message_t: pm message
+ *
+ * Returns 0 for success or negative error code for failure/busy
+ */
+int wcd9xxx_core_res_suspend(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ pm_message_t pmesg)
+{
+ int ret = 0;
+
+ pr_debug("%s: enter\n", __func__);
+ /*
+ * pm_qos_update_request() can be called after this suspend chain call
+ * started. thus suspend can be called while lock is being held
+ */
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) {
+ pr_debug("%s: suspending system, state %d, wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP;
+ } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) {
+ /*
+ * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+ * then set to WCD9XXX_PM_ASLEEP
+ */
+ pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+ if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq,
+ wcd9xxx_pm_cmpxchg(wcd9xxx_core_res,
+ WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_ASLEEP) ==
+ WCD9XXX_PM_SLEEPABLE,
+ HZ))) {
+ pr_debug("%s: suspend failed state %d, wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ ret = -EBUSY;
+ } else {
+ pr_debug("%s: done, state %d, wlock %d\n", __func__,
+ wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ }
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+ pr_warn("%s: system is already suspended, state %d, wlock %dn",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ }
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_suspend);
+
+/*
+ * wcd9xxx_core_res_resume:
+ * Resume callback function for wcd9xxx core
+ *
+ * @wcd9xxx_core_res: pointer to wcd core resource
+ *
+ * Returns 0 for success or negative error code for failure/busy
+ */
+int wcd9xxx_core_res_resume(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+ int ret = 0;
+
+ pr_debug("%s: enter\n", __func__);
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+ pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+ wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+ } else {
+ pr_warn("%s: system is already awake, state %d wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ }
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+ wake_up_all(&wcd9xxx_core_res->pm_wq);
+
+ return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_resume);
+
+/*
+ * wcd9xxx_get_intf_type:
+ * Get interface type of wcd9xxx core
+ *
+ * Returns interface type
+ */
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
+{
+ return wcd9xxx_intf;
+}
+EXPORT_SYMBOL(wcd9xxx_get_intf_type);
+
+/*
+ * wcd9xxx_set_intf_type:
+ * Set interface type of wcd9xxx core
+ *
+ */
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status)
+{
+ wcd9xxx_intf = intf_status;
+}
+EXPORT_SYMBOL(wcd9xxx_set_intf_type);
+
+/*
+ * wcd9xxx_set_power_state: set power state for the region
+ * @wcd9xxx: handle to wcd core
+ * @state: power state to be set
+ * @region: region index
+ *
+ * Returns error code in case of failure or 0 for success
+ */
+int wcd9xxx_set_power_state(struct wcd9xxx *wcd9xxx,
+ enum codec_power_states state,
+ enum wcd_power_regions region)
+{
+ if (!wcd9xxx) {
+ pr_err("%s: wcd9xxx is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) {
+ dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n",
+ __func__, region);
+ return -EINVAL;
+ }
+ if (!wcd9xxx->wcd9xxx_pwr[region]) {
+ dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n",
+ __func__, region);
+ return -EINVAL;
+ }
+ mutex_lock(&wcd9xxx->io_lock);
+ wcd9xxx->wcd9xxx_pwr[region]->power_state = state;
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_set_power_state);
+
+/*
+ * wcd9xxx_get_current_power_state: Get power state of the region
+ * @wcd9xxx: handle to wcd core
+ * @region: region index
+ *
+ * Returns current power state of the region or error code for failure
+ */
+int wcd9xxx_get_current_power_state(struct wcd9xxx *wcd9xxx,
+ enum wcd_power_regions region)
+{
+ int state;
+
+ if (!wcd9xxx) {
+ pr_err("%s: wcd9xxx is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((region < 0) || (region >= WCD9XXX_MAX_PWR_REGIONS)) {
+ dev_err(wcd9xxx->dev, "%s: region index %d out of bounds\n",
+ __func__, region);
+ return -EINVAL;
+ }
+ if (!wcd9xxx->wcd9xxx_pwr[region]) {
+ dev_err(wcd9xxx->dev, "%s: memory not created for region: %d\n",
+ __func__, region);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wcd9xxx->io_lock);
+ state = wcd9xxx->wcd9xxx_pwr[region]->power_state;
+ mutex_unlock(&wcd9xxx->io_lock);
+
+ return state;
+}
+EXPORT_SYMBOL(wcd9xxx_get_current_power_state);
+
diff --git a/include/linux/mfd/msm-cdc-supply.h b/include/linux/mfd/msm-cdc-supply.h
new file mode 100644
index 000000000000..b40f44b1f12f
--- /dev/null
+++ b/include/linux/mfd/msm-cdc-supply.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2016, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#ifndef __CODEC_POWER_SUPPLY_H__
+#define __CODEC_POWER_SUPPLY_H__
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+
+struct cdc_regulator {
+ const char *name;
+ int min_uV;
+ int max_uV;
+ int optimum_uA;
+ bool ondemand;
+ struct regulator *regulator;
+};
+
+extern int msm_cdc_get_power_supplies(struct device *dev,
+ struct cdc_regulator **cdc_vreg,
+ int *total_num_supplies);
+extern int msm_cdc_disable_static_supplies(struct device *dev,
+ struct regulator_bulk_data *supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies);
+extern int msm_cdc_release_supplies(struct device *dev,
+ struct regulator_bulk_data *supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies);
+extern int msm_cdc_enable_static_supplies(struct device *dev,
+ struct regulator_bulk_data *supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies);
+extern int msm_cdc_init_supplies(struct device *dev,
+ struct regulator_bulk_data **supplies,
+ struct cdc_regulator *cdc_vreg,
+ int num_supplies);
+#endif
diff --git a/include/linux/mfd/wcd9xxx/core-resource.h b/include/linux/mfd/wcd9xxx/core-resource.h
deleted file mode 100755
index fa32fd4b13ee..000000000000
--- a/include/linux/mfd/wcd9xxx/core-resource.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. 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 and
- * only 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.
- */
-
-#ifndef __MFD_CORE_RESOURCE_H__
-#define __MFD_CORE_RESOURCE_H__
-
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/pm_qos.h>
-
-#define WCD9XXX_MAX_IRQ_REGS 4
-#define WCD9XXX_MAX_NUM_IRQS (WCD9XXX_MAX_IRQ_REGS * 8)
-
-struct intr_data {
- int intr_num;
- bool clear_first;
-};
-
-enum wcd9xxx_pm_state {
- WCD9XXX_PM_SLEEPABLE,
- WCD9XXX_PM_AWAKE,
- WCD9XXX_PM_ASLEEP,
-};
-
-enum {
- WCD9XXX_INTR_STATUS_BASE = 0,
- WCD9XXX_INTR_CLEAR_BASE,
- WCD9XXX_INTR_MASK_BASE,
- WCD9XXX_INTR_LEVEL_BASE,
- WCD9XXX_INTR_CLR_COMMIT,
- WCD9XXX_INTR_REG_MAX,
-};
-
-enum wcd9xxx_intf_status {
- WCD9XXX_INTERFACE_TYPE_PROBING,
- WCD9XXX_INTERFACE_TYPE_SLIMBUS,
- WCD9XXX_INTERFACE_TYPE_I2C,
-};
-
-struct wcd9xxx_core_resource {
- struct mutex irq_lock;
- struct mutex nested_irq_lock;
-
- enum wcd9xxx_pm_state pm_state;
- struct mutex pm_lock;
- /* pm_wq notifies change of pm_state */
- wait_queue_head_t pm_wq;
- struct pm_qos_request pm_qos_req;
- int wlock_holders;
-
-
- /* holds the table of interrupts per codec */
- const struct intr_data *intr_table;
- int intr_table_size;
- unsigned int irq_base;
- unsigned int irq;
- u8 irq_masks_cur[WCD9XXX_MAX_IRQ_REGS];
- u8 irq_masks_cache[WCD9XXX_MAX_IRQ_REGS];
- bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
- int num_irqs;
- int num_irq_regs;
- u16 intr_reg[WCD9XXX_INTR_REG_MAX];
-
- /* Callback functions to read/write codec registers */
- int (*codec_reg_read) (struct wcd9xxx_core_resource *,
- unsigned short);
- int (*codec_reg_write) (struct wcd9xxx_core_resource *,
- unsigned short, u8);
- int (*codec_bulk_read) (struct wcd9xxx_core_resource *,
- unsigned short, int, u8 *);
- int (*codec_bulk_write) (struct wcd9xxx_core_resource *,
- unsigned short, int, u8 *);
-
- /* Pointer to parent container data structure */
- void *parent;
-
- struct device *dev;
-};
-
-extern int wcd9xxx_core_res_init(
- struct wcd9xxx_core_resource*,
- int, int,
- int (*codec_read)(struct wcd9xxx_core_resource *, unsigned short),
- int (*codec_write)(struct wcd9xxx_core_resource *, unsigned short, u8),
- int (*codec_bulk_read) (struct wcd9xxx_core_resource *, unsigned short,
- int, u8 *),
- int (*codec_bulk_write) (struct wcd9xxx_core_resource *, unsigned short,
- int, u8 *));
-
-extern void wcd9xxx_core_res_deinit(
- struct wcd9xxx_core_resource *);
-
-extern int wcd9xxx_core_res_suspend(
- struct wcd9xxx_core_resource *,
- pm_message_t);
-
-extern int wcd9xxx_core_res_resume(
- struct wcd9xxx_core_resource *);
-
-extern int wcd9xxx_core_irq_init(
- struct wcd9xxx_core_resource*);
-
-extern int wcd9xxx_initialize_irq(
- struct wcd9xxx_core_resource*,
- unsigned int,
- unsigned int);
-
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
-void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status);
-
-bool wcd9xxx_lock_sleep(struct wcd9xxx_core_resource *);
-void wcd9xxx_unlock_sleep(struct wcd9xxx_core_resource *);
-void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *);
-void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *);
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
- struct wcd9xxx_core_resource *,
- enum wcd9xxx_pm_state,
- enum wcd9xxx_pm_state);
-
-int wcd9xxx_request_irq(struct wcd9xxx_core_resource *, int,
- irq_handler_t, const char *, void *);
-
-void wcd9xxx_free_irq(struct wcd9xxx_core_resource *, int, void*);
-void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *, int);
-void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *, int);
-void wcd9xxx_disable_irq_sync(struct wcd9xxx_core_resource *, int);
-int wcd9xxx_reg_read(struct wcd9xxx_core_resource *,
- unsigned short);
-int wcd9xxx_reg_write(struct wcd9xxx_core_resource *,
- unsigned short, u8);
-int wcd9xxx_bulk_read(struct wcd9xxx_core_resource *,
- unsigned short, int, u8 *);
-int wcd9xxx_bulk_write(struct wcd9xxx_core_resource*,
- unsigned short, int, u8*);
-int wcd9xxx_reg_update_bits(struct wcd9xxx_core_resource *core_res,
- unsigned short reg, u8 mask, u8 val);
-int wcd9xxx_irq_init(struct wcd9xxx_core_resource *);
-void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *);
-int wcd9xxx_core_res_resume(
- struct wcd9xxx_core_resource *);
-int wcd9xxx_core_res_suspend(
- struct wcd9xxx_core_resource *,
- pm_message_t);
-#endif
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index e0abd4285753..96937a4338a8 100755..100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -16,9 +16,11 @@
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/of_irq.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
-
+#include <linux/interrupt.h>
+#include <linux/pm_qos.h>
+#define WCD9XXX_MAX_IRQ_REGS 4
+#define WCD9XXX_MAX_NUM_IRQS (WCD9XXX_MAX_IRQ_REGS * 8)
#define WCD9XXX_SLIM_NUM_PORT_REG 3
#define TABLA_VERSION_1_0 0
#define TABLA_VERSION_1_1 1
@@ -58,9 +60,15 @@
#define TASHA_IS_2_0(ver) \
((ver == TASHA_VERSION_2_0) ? 1 : 0)
-enum wcd9xxx_slim_slave_addr_type {
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA,
- WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TAIKO,
+#define IS_CODEC_TYPE(wcd, wcdtype) \
+ ((wcd->type == wcdtype) ? true : false)
+#define IS_CODEC_VERSION(wcd, wcdversion) \
+ ((wcd->version == wcdversion) ? true : false)
+
+enum {
+ CDC_V_1_0,
+ CDC_V_1_1,
+ CDC_V_2_0,
};
enum codec_variant {
@@ -70,6 +78,32 @@ enum codec_variant {
WCD9326,
};
+enum wcd9xxx_slim_slave_addr_type {
+ WCD9XXX_SLIM_SLAVE_ADDR_TYPE_0,
+ WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1,
+};
+
+enum wcd9xxx_pm_state {
+ WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_AWAKE,
+ WCD9XXX_PM_ASLEEP,
+};
+
+enum {
+ WCD9XXX_INTR_STATUS_BASE = 0,
+ WCD9XXX_INTR_CLEAR_BASE,
+ WCD9XXX_INTR_MASK_BASE,
+ WCD9XXX_INTR_LEVEL_BASE,
+ WCD9XXX_INTR_CLR_COMMIT,
+ WCD9XXX_INTR_REG_MAX,
+};
+
+enum wcd9xxx_intf_status {
+ WCD9XXX_INTERFACE_TYPE_PROBING,
+ WCD9XXX_INTERFACE_TYPE_SLIMBUS,
+ WCD9XXX_INTERFACE_TYPE_I2C,
+};
+
enum {
/* INTR_REG 0 */
WCD9XXX_IRQ_SLIMBUS = 0,
@@ -128,50 +162,47 @@ enum {
};
enum {
- /* INTR_REG 0 */
- WCD9335_IRQ_FLL_LOCK_LOSS = 1,
- WCD9335_IRQ_HPH_PA_OCPL_FAULT,
- WCD9335_IRQ_HPH_PA_OCPR_FAULT,
- WCD9335_IRQ_EAR_PA_OCP_FAULT,
- WCD9335_IRQ_HPH_PA_CNPL_COMPLETE,
- WCD9335_IRQ_HPH_PA_CNPR_COMPLETE,
- WCD9335_IRQ_EAR_PA_CNP_COMPLETE,
- /* INTR_REG 1 */
- WCD9335_IRQ_MBHC_SW_DET,
- WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
- WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
- WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
- WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
- WCD9335_IRQ_RESERVED_0,
- WCD9335_IRQ_RESERVED_1,
- WCD9335_IRQ_RESERVED_2,
- /* INTR_REG 2 */
- WCD9335_IRQ_LINE_PA1_CNP_COMPLETE,
- WCD9335_IRQ_LINE_PA2_CNP_COMPLETE,
- WCD9335_IRQ_LINE_PA3_CNP_COMPLETE,
- WCD9335_IRQ_LINE_PA4_CNP_COMPLETE,
- WCD9335_IRQ_SOUNDWIRE,
- WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE,
- WCD9335_IRQ_RCO_ERROR,
- WCD9335_IRQ_SVA_ERROR,
- /* INTR_REG 3 */
- WCD9335_IRQ_MAD_AUDIO,
- WCD9335_IRQ_MAD_BEACON,
- WCD9335_IRQ_MAD_ULTRASOUND,
- WCD9335_IRQ_VBAT_ATTACK,
- WCD9335_IRQ_VBAT_RESTORE,
- WCD9335_IRQ_SVA_OUTBOX1,
- WCD9335_IRQ_SVA_OUTBOX2,
- WCD9335_NUM_IRQS,
-};
-
-enum {
TABLA_NUM_IRQS = WCD9310_NUM_IRQS,
SITAR_NUM_IRQS = WCD9310_NUM_IRQS,
TAIKO_NUM_IRQS = WCD9XXX_NUM_IRQS,
TAPAN_NUM_IRQS = WCD9306_NUM_IRQS,
TOMTOM_NUM_IRQS = WCD9330_NUM_IRQS,
- TASHA_NUM_IRQS = WCD9335_NUM_IRQS,
+};
+
+struct intr_data {
+ int intr_num;
+ bool clear_first;
+};
+
+struct wcd9xxx_core_resource {
+ struct mutex irq_lock;
+ struct mutex nested_irq_lock;
+
+ enum wcd9xxx_pm_state pm_state;
+ struct mutex pm_lock;
+ /* pm_wq notifies change of pm_state */
+ wait_queue_head_t pm_wq;
+ struct pm_qos_request pm_qos_req;
+ int wlock_holders;
+
+
+ /* holds the table of interrupts per codec */
+ const struct intr_data *intr_table;
+ int intr_table_size;
+ unsigned int irq_base;
+ unsigned int irq;
+ u8 irq_masks_cur[WCD9XXX_MAX_IRQ_REGS];
+ u8 irq_masks_cache[WCD9XXX_MAX_IRQ_REGS];
+ bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
+ int num_irqs;
+ int num_irq_regs;
+ u16 intr_reg[WCD9XXX_INTR_REG_MAX];
+ struct regmap *wcd_core_regmap;
+
+ /* Pointer to parent container data structure */
+ void *parent;
+
+ struct device *dev;
};
/*
@@ -243,6 +274,9 @@ struct wcd9xxx_codec_type {
int version; /* -1 to retrive version from chip version register */
enum wcd9xxx_slim_slave_addr_type slim_slave_type;
u16 i2c_chip_status;
+ const struct intr_data *intr_tbl;
+ int intr_tbl_size;
+ u16 intr_reg[WCD9XXX_INTR_REG_MAX];
};
struct wcd9xxx_power_region {
@@ -266,6 +300,8 @@ struct wcd9xxx {
int bytes, void *dest, bool interface_reg);
int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg);
+ int (*multi_reg_write)(struct wcd9xxx *wcd9xxx, const void *data,
+ size_t count);
int (*dev_down)(struct wcd9xxx *wcd9xxx);
int (*post_reset)(struct wcd9xxx *wcd9xxx);
@@ -287,10 +323,9 @@ struct wcd9xxx {
struct wcd9xxx_ch *tx_chs;
u32 mclk_rate;
enum codec_variant type;
- bool using_regmap;
struct regmap *regmap;
- const struct wcd9xxx_codec_type *codec_type;
+ struct wcd9xxx_codec_type *codec_type;
bool prev_pg_valid;
u8 prev_pg;
struct wcd9xxx_power_region *wcd9xxx_pwr[WCD9XXX_MAX_PWR_REGIONS];
@@ -315,26 +350,43 @@ int wcd9xxx_set_power_state(struct wcd9xxx *, enum codec_power_states,
int wcd9xxx_get_current_power_state(struct wcd9xxx *,
enum wcd_power_regions);
+int wcd9xxx_page_write(struct wcd9xxx *wcd9xxx, unsigned short *reg);
+
int wcd9xxx_slim_bulk_write(struct wcd9xxx *wcd9xxx,
struct wcd9xxx_reg_val *bulk_reg,
unsigned int size, bool interface);
+extern int wcd9xxx_core_res_init(
+ struct wcd9xxx_core_resource*,
+ int, int, struct regmap *);
+
+extern void wcd9xxx_core_res_deinit(
+ struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_res_suspend(
+ struct wcd9xxx_core_resource *,
+ pm_message_t);
+
+extern int wcd9xxx_core_res_resume(
+ struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_irq_init(
+ struct wcd9xxx_core_resource*);
+
+extern int wcd9xxx_assign_irq(struct wcd9xxx_core_resource*,
+ unsigned int,
+ unsigned int);
+
+extern enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
+extern void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status);
+
+extern enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+ struct wcd9xxx_core_resource *,
+ enum wcd9xxx_pm_state,
+ enum wcd9xxx_pm_state);
static inline int __init wcd9xxx_irq_of_init(struct device_node *node,
struct device_node *parent)
{
return 0;
}
-
-static inline void wcd9xxx_reg_update(struct wcd9xxx *core,
- unsigned short reg,
- u8 mask, u8 val)
-{
- u8 reg_val;
-
- if (core) {
- reg_val = wcd9xxx_reg_read(&core->core_res, reg);
- reg_val = (reg_val & ~mask) | (val & mask);
- wcd9xxx_reg_write(&core->core_res, reg, reg_val);
- }
-}
#endif
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index 791cb7f1654a..52277f26b5a4 100755
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -10,11 +10,12 @@
* GNU General Public License for more details.
*/
-#ifndef __MFD_TABLA_PDATA_H__
+#ifndef __MFD_WCD9XXX_PDATA_H__
-#define __MFD_TABLA_PDATA_H__
+#define __MFD_WCD9XXX_PDATA_H__
#include <linux/slimbus/slimbus.h>
+#include <linux/mfd/msm-cdc-supply.h>
#define MICBIAS_EXT_BYP_CAP 0x00
#define MICBIAS_NO_EXT_BYP_CAP 0x01
@@ -183,12 +184,12 @@ struct wcd9xxx_pdata {
struct slim_device slimbus_slave_device;
struct wcd9xxx_micbias_setting micbias;
struct wcd9xxx_ocp_setting ocp;
- struct wcd9xxx_regulator regulator[WCD9XXX_MAX_REGULATOR];
+ struct cdc_regulator *regulator;
+ int num_supplies;
u32 mclk_rate;
u32 dmic_sample_rate;
u32 mad_dmic_sample_rate;
u32 dmic_clk_drv;
- enum codec_variant cdc_variant;
u16 use_pinctrl;
};
diff --git a/include/linux/mfd/wcd9xxx/wcd-gpio-ctrl.h b/include/linux/mfd/wcd9xxx/wcd-gpio-ctrl.h
deleted file mode 100644
index 1260c33d1003..000000000000
--- a/include/linux/mfd/wcd9xxx/wcd-gpio-ctrl.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (c) 2016, The Linux Foundation. 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 and
- * only 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.
- */
-
-#ifndef __MFD_CDC_GPIO_CTRL_H_
-#define __MFD_CDC_GPIO_CTRL_H_
-
-#include <linux/types.h>
-#include <linux/of.h>
-
-#ifdef CONFIG_WCD9335_CODEC
-extern int wcd_gpio_ctrl_select_sleep_state(struct device_node *);
-extern int wcd_gpio_ctrl_select_active_state(struct device_node *);
-
-#else
-int wcd_gpio_ctrl_select_sleep_state(struct device_node *np)
-{
- return 0;
-}
-int wcd_gpio_ctrl_select_active_state(struct device_node *np)
-{
- return 0;
-}
-#endif
-
-#endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-irq.h b/include/linux/mfd/wcd9xxx/wcd9xxx-irq.h
new file mode 100644
index 000000000000..f1b7a4320ad1
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-irq.h
@@ -0,0 +1,32 @@
+/* Copyright (c) 2016, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#include <linux/types.h>
+#include <linux/mfd/wcd9xxx/core.h>
+
+#ifndef __MFD_WCD9XXX_IRQ_H
+#define __MFD_WCD9XXX_IRQ_H
+bool wcd9xxx_lock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_unlock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *);
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *, int,
+ irq_handler_t, const char *, void *);
+
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *, int, void*);
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq_sync(struct wcd9xxx_core_resource *, int);
+
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *);
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *);
+#endif
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h b/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h
new file mode 100644
index 000000000000..441d70b97f4e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h
@@ -0,0 +1,119 @@
+/* Copyright (c) 2016, The Linux Foundation. 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 and
+ * only 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.
+ */
+
+#ifndef __WCD9XXX_UTILS_H__
+#define __WCD9XXX_UTILS_H__
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/mfd/wcd9xxx/core.h>
+
+struct wcd9xxx_pdata *wcd9xxx_populate_dt_data(struct device *dev);
+int wcd9xxx_bringup(struct device *dev);
+int wcd9xxx_bringdown(struct device *dev);
+struct regmap *wcd9xxx_regmap_init(struct device *,
+ const struct regmap_config *);
+int wcd9xxx_reset(struct device *dev);
+int wcd9xxx_reset_low(struct device *dev);
+int wcd9xxx_get_codec_info(struct device *dev);
+
+typedef int (*codec_bringup_fn)(struct wcd9xxx *);
+typedef int (*codec_bringdown_fn)(struct wcd9xxx *);
+typedef int (*codec_type_fn)(struct wcd9xxx *,
+ struct wcd9xxx_codec_type *);
+
+#ifdef CONFIG_WCD9335_CODEC
+extern int wcd9335_bringup(struct wcd9xxx *wcd9xxx);
+extern int wcd9335_bringdown(struct wcd9xxx *wcd9xxx);
+extern int wcd9335_get_codec_info(struct wcd9xxx *,
+ struct wcd9xxx_codec_type *);
+#endif
+
+#ifdef CONFIG_WCD9330_CODEC
+extern int wcd9330_bringup(struct wcd9xxx *wcd9xxx);
+extern int wcd9330_bringdown(struct wcd9xxx *wcd9xxx);
+extern int wcd9330_get_codec_info(struct wcd9xxx *,
+ struct wcd9xxx_codec_type *);
+#endif
+
+static inline codec_bringdown_fn wcd9xxx_bringdown_fn(int type)
+{
+ codec_bringdown_fn cdc_bdown_fn;
+
+ switch (type) {
+#ifdef CONFIG_WCD9335_CODEC
+ case WCD9335:
+ cdc_bdown_fn = wcd9335_bringdown;
+ break;
+#endif
+#ifdef CONFIG_WCD9330_CODEC
+ case WCD9330:
+ cdc_bdown_fn = wcd9330_bringdown;
+ break;
+#endif
+ default:
+ cdc_bdown_fn = NULL;
+ break;
+ }
+
+ return cdc_bdown_fn;
+}
+
+static inline codec_bringup_fn wcd9xxx_bringup_fn(int type)
+{
+ codec_bringup_fn cdc_bup_fn;
+
+ switch (type) {
+#ifdef CONFIG_WCD9335_CODEC
+ case WCD9335:
+ cdc_bup_fn = wcd9335_bringup;
+ break;
+#endif
+#ifdef CONFIG_WCD9330_CODEC
+ case WCD9330:
+ cdc_bup_fn = wcd9330_bringup;
+ break;
+#endif
+ default:
+ cdc_bup_fn = NULL;
+ break;
+ }
+
+ return cdc_bup_fn;
+}
+
+static inline codec_type_fn wcd9xxx_get_codec_info_fn(int type)
+{
+ codec_type_fn cdc_type_fn;
+
+ switch (type) {
+#ifdef CONFIG_WCD9335_CODEC
+ case WCD9335:
+ cdc_type_fn = wcd9335_get_codec_info;
+ break;
+#endif
+#ifdef CONFIG_WCD9330_CODEC
+ case WCD9330:
+ cdc_type_fn = wcd9330_get_codec_info;
+ break;
+#endif
+ default:
+ cdc_type_fn = NULL;
+ break;
+ }
+
+ return cdc_type_fn;
+}
+#endif
+
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0f41d8ab1417..913bc0e06098 100755
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -722,6 +722,7 @@ config SND_SOC_WCD9330
config SND_SOC_WCD9335
tristate
+ depends on WCD9335_CODEC
config SND_SOC_WSA881X
tristate
diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c
index e99337cb63d4..84368d817dc9 100644
--- a/sound/soc/codecs/wcd9330.c
+++ b/sound/soc/codecs/wcd9330.c
@@ -20,7 +20,9 @@
#include <linux/debugfs.h>
#include <linux/wait.h>
#include <linux/bitops.h>
+#include <linux/regmap.h>
#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9330_registers.h>
#include <linux/mfd/wcd9xxx/pdata.h>
@@ -521,6 +523,45 @@ static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
0, /* AIF2_CAP */
};
+/*
+ * Interrupt table for v3 corresponds to newer version
+ * codecs (wcd9330)
+ */
+static const struct intr_data wcd9330_intr_tbl[] = {
+ {WCD9XXX_IRQ_SLIMBUS, false},
+ {WCD9XXX_IRQ_MBHC_INSERTION, true},
+ {WCD9XXX_IRQ_MBHC_POTENTIAL, true},
+ {WCD9XXX_IRQ_MBHC_RELEASE, true},
+ {WCD9XXX_IRQ_MBHC_PRESS, true},
+ {WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
+ {WCD9XXX_IRQ_MBHC_REMOVAL, true},
+ {WCD9330_IRQ_MBHC_JACK_SWITCH, true},
+ {WCD9XXX_IRQ_BG_PRECHARGE, false},
+ {WCD9XXX_IRQ_PA1_STARTUP, false},
+ {WCD9XXX_IRQ_PA2_STARTUP, false},
+ {WCD9XXX_IRQ_PA3_STARTUP, false},
+ {WCD9XXX_IRQ_PA4_STARTUP, false},
+ {WCD9XXX_IRQ_PA5_STARTUP, false},
+ {WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+ {WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
+ {WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
+ {WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
+ {WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
+ {WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
+ {WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
+ {WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
+ {WCD9320_IRQ_EAR_PA_STARTUP, false},
+ {WCD9330_IRQ_SVASS_ERR_EXCEPTION, false},
+ {WCD9330_IRQ_SVASS_ENGINE, true},
+ {WCD9330_IRQ_MAD_AUDIO, false},
+ {WCD9330_IRQ_MAD_BEACON, false},
+ {WCD9330_IRQ_MAD_ULTRASOUND, false},
+ {WCD9330_IRQ_SPEAKER1_CLIPPING, false},
+ {WCD9330_IRQ_SPEAKER2_CLIPPING, false},
+ {WCD9330_IRQ_VBAT_MONITOR_ATTACK, false},
+ {WCD9330_IRQ_VBAT_MONITOR_RELEASE, false},
+};
+
struct tomtom_priv {
struct snd_soc_codec *codec;
u32 adc_count;
@@ -683,6 +724,121 @@ static unsigned short tx_digital_gain_reg[] = {
TOMTOM_A_CDC_TX10_VOL_CTL_GAIN,
};
+/*
+ * wcd9330_get_codec_info: Get codec specific information
+ *
+ * @wcd9xxx: pointer to wcd9xxx structure
+ * @wcd_type: pointer to wcd9xxx_codec_type structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+int wcd9330_get_codec_info(struct wcd9xxx *wcd9xxx,
+ struct wcd9xxx_codec_type *wcd_type)
+{
+ u16 id_minor, id_major;
+ struct regmap *wcd_regmap;
+ int rc, val, version = 0;
+
+ if (!wcd9xxx || !wcd_type)
+ return -EINVAL;
+
+ if (!wcd9xxx->regmap) {
+ dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+ __func__);
+ return -EINVAL;
+ }
+ wcd_regmap = wcd9xxx->regmap;
+ rc = regmap_bulk_read(wcd_regmap, TOMTOM_A_CHIP_ID_BYTE_0,
+ (u8 *)&id_minor, sizeof(u16));
+ if (rc)
+ return -EINVAL;
+
+ rc = regmap_bulk_read(wcd_regmap, TOMTOM_A_CHIP_ID_BYTE_2,
+ (u8 *)&id_major, sizeof(u16));
+ if (rc)
+ return -EINVAL;
+
+ dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+ __func__, id_major, id_minor);
+
+ if (id_minor == cpu_to_le16(0x1))
+ version = 2;
+ else if (id_minor == cpu_to_le16(0x0))
+ version = 1;
+ else
+ dev_err(wcd9xxx->dev, "%s: wcd9330 version unknown (major 0x%x, minor 0x%x)\n",
+ __func__, id_major, id_minor);
+
+ /* Fill codec type info */
+ wcd_type->id_major = id_major;
+ wcd_type->id_minor = id_minor;
+ wcd_type->num_irqs = WCD9330_NUM_IRQS;
+ wcd_type->version = version;
+ wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
+ wcd_type->i2c_chip_status = 0x01;
+ wcd_type->intr_tbl = wcd9330_intr_tbl;
+ wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9330_intr_tbl);
+
+ wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
+ TOMTOM_A_INTR1_STATUS0;
+ wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
+ TOMTOM_A_INTR1_CLEAR0;
+ wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
+ TOMTOM_A_INTR1_MASK0;
+ wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
+ TOMTOM_A_INTR1_LEVEL0;
+ wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
+ TOMTOM_A_INTR_MODE;
+
+ return rc;
+}
+EXPORT_SYMBOL(wcd9330_get_codec_info);
+
+/*
+ * wcd9330_bringdown: Bringdown WCD Codec
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+int wcd9330_bringdown(struct wcd9xxx *wcd9xxx)
+{
+ if (!wcd9xxx || !wcd9xxx->regmap)
+ return -EINVAL;
+
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x7);
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x6);
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0xe);
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x8);
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9330_bringdown);
+
+/*
+ * wcd9330_bringup: Bring up WCD Codec
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+int wcd9330_bringup(struct wcd9xxx *wcd9xxx)
+{
+ if (!wcd9xxx || !wcd9xxx->regmap)
+ return -EINVAL;
+
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x4);
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_CDC_CTL, 0x0);
+ /* wait for 5ms after codec reset for it to complete */
+ usleep_range(5000, 5100);
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_CDC_CTL, 0x1);
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_LEAKAGE_CTL, 0x3);
+ regmap_write(wcd9xxx->regmap, TOMTOM_A_CDC_CTL, 0x3);
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9330_bringup);
+
int tomtom_enable_qfuse_sensing(struct snd_soc_codec *codec)
{
struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec);
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 7ba7ec93b779..990d22fad45a 100755
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -21,7 +21,9 @@
#include <linux/debugfs.h>
#include <linux/wait.h>
#include <linux/bitops.h>
+#include <linux/regmap.h>
#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9335/registers.h>
#include <linux/mfd/wcd9xxx/pdata.h>
@@ -532,6 +534,38 @@ enum {
SPLINE_SRC_MAX,
};
+/* wcd9335 interrupt table */
+static const struct intr_data wcd9335_intr_table[] = {
+ {WCD9XXX_IRQ_SLIMBUS, false},
+ {WCD9335_IRQ_MBHC_SW_DET, true},
+ {WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true},
+ {WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true},
+ {WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true},
+ {WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
+ {WCD9335_IRQ_FLL_LOCK_LOSS, false},
+ {WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false},
+ {WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false},
+ {WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false},
+ {WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false},
+ {WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false},
+ {WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false},
+ {WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false},
+ {WCD9335_IRQ_HPH_PA_OCPL_FAULT, false},
+ {WCD9335_IRQ_HPH_PA_OCPR_FAULT, false},
+ {WCD9335_IRQ_EAR_PA_OCP_FAULT, false},
+ {WCD9335_IRQ_SOUNDWIRE, false},
+ {WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false},
+ {WCD9335_IRQ_RCO_ERROR, false},
+ {WCD9335_IRQ_SVA_ERROR, false},
+ {WCD9335_IRQ_MAD_AUDIO, false},
+ {WCD9335_IRQ_MAD_BEACON, false},
+ {WCD9335_IRQ_SVA_OUTBOX1, true},
+ {WCD9335_IRQ_SVA_OUTBOX2, true},
+ {WCD9335_IRQ_MAD_ULTRASOUND, false},
+ {WCD9335_IRQ_VBAT_ATTACK, false},
+ {WCD9335_IRQ_VBAT_RESTORE, false},
+};
+
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -816,6 +850,176 @@ static const struct tasha_reg_mask_val tasha_spkr_mode1[] = {
{WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
};
+/*
+ * wcd9335_get_codec_info: Get codec specific information
+ *
+ * @wcd9xxx: pointer to wcd9xxx structure
+ * @wcd_type: pointer to wcd9xxx_codec_type structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+int wcd9335_get_codec_info(struct wcd9xxx *wcd9xxx,
+ struct wcd9xxx_codec_type *wcd_type)
+{
+ u16 id_minor, id_major;
+ struct regmap *wcd_regmap;
+ int rc, val, version = 0;
+
+ if (!wcd9xxx || !wcd_type)
+ return -EINVAL;
+
+ if (!wcd9xxx->regmap) {
+ dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+ __func__);
+ return -EINVAL;
+ }
+ wcd_regmap = wcd9xxx->regmap;
+
+ rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+ (u8 *)&id_minor, sizeof(u16));
+ if (rc)
+ return -EINVAL;
+
+ rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
+ (u8 *)&id_major, sizeof(u16));
+ if (rc)
+ return -EINVAL;
+
+ dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+ __func__, id_major, id_minor);
+
+ /* Version detection */
+ if (id_major == TASHA_MAJOR) {
+ regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,
+ &val);
+ version = ((u8)val & 0x80) >> 7;
+ } else if (id_major == TASHA2P0_MAJOR)
+ version = 2;
+ else
+ dev_err(wcd9xxx->dev, "%s: wcd9335 version unknown (major 0x%x, minor 0x%x)\n",
+ __func__, id_major, id_minor);
+
+ /* Fill codec type info */
+ wcd_type->id_major = id_major;
+ wcd_type->id_minor = id_minor;
+ wcd_type->num_irqs = WCD9335_NUM_IRQS;
+ wcd_type->version = version;
+ wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
+ wcd_type->i2c_chip_status = 0x01;
+ wcd_type->intr_tbl = wcd9335_intr_table;
+ wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9335_intr_table);
+
+ wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
+ WCD9335_INTR_PIN1_STATUS0;
+ wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
+ WCD9335_INTR_PIN1_CLEAR0;
+ wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
+ WCD9335_INTR_PIN1_MASK0;
+ wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
+ WCD9335_INTR_LEVEL0;
+ wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
+ WCD9335_INTR_CLR_COMMIT;
+
+ return rc;
+}
+EXPORT_SYMBOL(wcd9335_get_codec_info);
+
+/*
+ * wcd9335_bringdown: Bringdown WCD Codec
+ *
+ * @wcd9xxx: Pointer to wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+int wcd9335_bringdown(struct wcd9xxx *wcd9xxx)
+{
+ if (!wcd9xxx || !wcd9xxx->regmap)
+ return -EINVAL;
+
+ regmap_write(wcd9xxx->regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x04);
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9335_bringdown);
+
+/*
+ * wcd9335_bringup: Bringup WCD Codec
+ *
+ * @wcd9xxx: Pointer to the wcd9xxx structure
+ *
+ * Returns 0 for success or negative error code for failure
+ */
+int wcd9335_bringup(struct wcd9xxx *wcd9xxx)
+{
+ int ret = 0;
+ int val, byte0;
+ struct regmap *wcd_regmap;
+
+ if (!wcd9xxx)
+ return -EINVAL;
+
+ if (!wcd9xxx->regmap) {
+ dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
+ __func__);
+ return -EINVAL;
+ }
+ wcd_regmap = wcd9xxx->regmap;
+
+ regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val);
+ regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0);
+
+ if ((val < 0) || (byte0 < 0)) {
+ dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n",
+ __func__);
+ return -EINVAL;
+ }
+ if ((val & 0x80) && (byte0 == 0x0)) {
+ dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n",
+ __func__);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+ regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+ regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x5);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x7);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x3);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+ } else if (byte0 == 0x1) {
+ dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n",
+ __func__);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+ regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00);
+ regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
+ regmap_write(wcd_regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x5);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x7);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x3);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+ } else if ((byte0 == 0) && (!(val & 0x80))) {
+ dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n",
+ __func__);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+ regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+ regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+ 0x3);
+ regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+ } else {
+ dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n",
+ __func__);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(wcd9335_bringup);
+
/**
* tasha_set_spkr_gain_offset - offset the speaker path
* gain with the given offset value.
@@ -1592,7 +1796,7 @@ static inline void tasha_mbhc_get_result_params(struct wcd9xxx *wcd9xxx,
int32_t *zdet)
{
int i;
- u16 val;
+ int val, val1;
s16 c1;
s32 x1, d1;
int32_t denom;
@@ -1600,19 +1804,16 @@ static inline void tasha_mbhc_get_result_params(struct wcd9xxx *wcd9xxx,
3277, 1639, 820, 410, 205, 103, 52, 26
};
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ZDET, 0x20, 0x20);
+ regmap_update_bits(wcd9xxx->regmap, WCD9335_ANA_MBHC_ZDET, 0x20, 0x20);
for (i = 0; i < TASHA_ZDET_NUM_MEASUREMENTS; i++) {
- val = wcd9xxx_reg_read(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_RESULT_2);
+ regmap_read(wcd9xxx->regmap, WCD9335_ANA_MBHC_RESULT_2, &val);
if (val & 0x80)
break;
}
val = val << 0x8;
- val |= wcd9xxx_reg_read(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_RESULT_1);
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ZDET, 0x20, 0x00);
+ regmap_read(wcd9xxx->regmap, WCD9335_ANA_MBHC_RESULT_1, &val1);
+ val |= val1;
+ regmap_update_bits(wcd9xxx->regmap, WCD9335_ANA_MBHC_ZDET, 0x20, 0x00);
x1 = TASHA_MBHC_GET_X1(val);
c1 = TASHA_MBHC_GET_C1(val);
/* If ramp is not complete, give additional 5ms */
@@ -1637,8 +1838,8 @@ static inline void tasha_mbhc_get_result_params(struct wcd9xxx *wcd9xxx,
ramp_down:
i = 0;
while (x1) {
- wcd9xxx_bulk_read(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_RESULT_1, 2, (u8 *)&val);
+ regmap_bulk_read(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_RESULT_1, (u8 *)&val, 2);
x1 = TASHA_MBHC_GET_X1(val);
i++;
if (i == TASHA_ZDET_NUM_MEASUREMENTS)
@@ -1691,13 +1892,13 @@ static void tasha_mbhc_zdet_ramp(struct snd_soc_codec *codec,
if (!zl)
goto z_right;
/* Start impedance measurement for HPH_L */
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ZDET, 0x80, 0x80);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_ZDET, 0x80, 0x80);
dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_L, noff = %d\n",
__func__, zdet_param->noff);
tasha_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet);
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ZDET, 0x80, 0x00);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_ZDET, 0x80, 0x00);
*zl = zdet;
@@ -1705,13 +1906,13 @@ z_right:
if (!zr)
return;
/* Start impedance measurement for HPH_R */
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ZDET, 0x40, 0x40);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_ZDET, 0x40, 0x40);
dev_dbg(wcd9xxx->dev, "%s: ramp for HPH_R, noff = %d\n",
__func__, zdet_param->noff);
tasha_mbhc_get_result_params(wcd9xxx, d1_a, zdet_param->noff, &zdet);
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ZDET, 0x40, 0x00);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_ZDET, 0x40, 0x00);
*zr = zdet;
}
@@ -1780,23 +1981,22 @@ static void tasha_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
reg3 = snd_soc_read(codec, WCD9335_MBHC_CTL_1);
reg4 = snd_soc_read(codec, WCD9335_MBHC_ZDET_ANA_CTL);
- if (wcd9xxx_reg_read(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ELECT) & 0x80) {
+ if (snd_soc_read(codec, WCD9335_ANA_MBHC_ELECT) & 0x80) {
is_fsm_disable = true;
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ELECT, 0x80, 0x00);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_ELECT, 0x80, 0x00);
}
/* For NO-jack, disable L_DET_EN before Z-det measurements */
if (mbhc->hphl_swh)
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_MECH, 0x80, 0x00);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_MECH, 0x80, 0x00);
/* Enable AZ */
snd_soc_update_bits(codec, WCD9335_MBHC_CTL_1, 0x0C, 0x04);
/* Turn off 100k pull down on HPHL */
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_MECH, 0x01, 0x00);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_MECH, 0x01, 0x00);
/* First get impedance on Left */
d1 = d1_a[1];
@@ -1911,19 +2111,19 @@ zdet_complete:
snd_soc_write(codec, WCD9335_ANA_MBHC_BTN6, reg1);
snd_soc_write(codec, WCD9335_ANA_MBHC_BTN7, reg2);
/* Turn on 100k pull down on HPHL */
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_MECH, 0x01, 0x01);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_MECH, 0x01, 0x01);
/* For NO-jack, re-enable L_DET_EN after Z-det measurements */
if (mbhc->hphl_swh)
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_MECH, 0x80, 0x80);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_MECH, 0x80, 0x80);
snd_soc_write(codec, WCD9335_MBHC_ZDET_ANA_CTL, reg4);
snd_soc_write(codec, WCD9335_MBHC_CTL_1, reg3);
if (is_fsm_disable)
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- WCD9335_ANA_MBHC_ELECT, 0x80, 0x80);
+ regmap_update_bits(wcd9xxx->regmap,
+ WCD9335_ANA_MBHC_ELECT, 0x80, 0x80);
if (tasha->zdet_gpio_cb && is_change)
tasha->zdet_gpio_cb(codec, false);
}
@@ -11776,18 +11976,18 @@ static void tasha_update_reg_defaults(struct tasha_priv *tasha)
wcd9xxx = tasha->wcd9xxx;
for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_defaults); i++)
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- tasha_codec_reg_defaults[i].reg,
- tasha_codec_reg_defaults[i].mask,
- tasha_codec_reg_defaults[i].val);
+ regmap_update_bits(wcd9xxx->regmap,
+ tasha_codec_reg_defaults[i].reg,
+ tasha_codec_reg_defaults[i].mask,
+ tasha_codec_reg_defaults[i].val);
tasha->intf_type = wcd9xxx_get_intf_type();
if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_i2c_defaults); i++)
- wcd9xxx_reg_update_bits(&wcd9xxx->core_res,
- tasha_codec_reg_i2c_defaults[i].reg,
- tasha_codec_reg_i2c_defaults[i].mask,
- tasha_codec_reg_i2c_defaults[i].val);
+ regmap_update_bits(wcd9xxx->regmap,
+ tasha_codec_reg_i2c_defaults[i].reg,
+ tasha_codec_reg_i2c_defaults[i].mask,
+ tasha_codec_reg_i2c_defaults[i].val);
return;
}
@@ -12919,15 +13119,15 @@ static int tasha_swrm_read(void *handle, int reg)
swr_rd_data_base = WCD9335_SWR_AHB_BRIDGE_RD_DATA_0;
/* read_lock */
mutex_lock(&tasha->swr_read_lock);
- ret = wcd9xxx_bulk_write(&wcd9xxx->core_res, swr_rd_addr_base, 4,
- (u8 *)&reg);
+ ret = regmap_bulk_write(wcd9xxx->regmap, swr_rd_addr_base,
+ (u8 *)&reg, 4);
if (ret < 0) {
pr_err("%s: RD Addr Failure\n", __func__);
goto err;
}
/* Check for RD status */
- ret = wcd9xxx_bulk_read(&wcd9xxx->core_res, swr_rd_data_base, 4,
- (u8 *)&val);
+ ret = regmap_bulk_read(wcd9xxx->regmap, swr_rd_data_base,
+ (u8 *)&val, 4);
if (ret < 0) {
pr_err("%s: RD Data Failure\n", __func__);
goto err;
@@ -12952,16 +13152,16 @@ static int tasha_swrm_i2s_bulk_write(struct wcd9xxx *wcd9xxx,
for (i = 0; i < (len * 2); i += 2) {
/* First Write the Data to register */
- ret = wcd9xxx_bulk_write(&wcd9xxx->core_res,
- swr_wr_data_base, 4, bulk_reg[i].buf);
+ ret = regmap_bulk_write(wcd9xxx->regmap,
+ swr_wr_data_base, bulk_reg[i].buf, 4);
if (ret < 0) {
dev_err(wcd9xxx->dev, "%s: WR Data Failure\n",
__func__);
break;
}
/* Next Write Address */
- ret = wcd9xxx_bulk_write(&wcd9xxx->core_res,
- swr_wr_addr_base, 4, bulk_reg[i+1].buf);
+ ret = regmap_bulk_write(wcd9xxx->regmap,
+ swr_wr_addr_base, bulk_reg[i+1].buf, 4);
if (ret < 0) {
dev_err(wcd9xxx->dev, "%s: WR Addr Failure\n",
__func__);
@@ -13087,25 +13287,25 @@ static int tasha_swrm_clock(void *handle, bool enable)
tasha->swr_clk_users++;
if (tasha->swr_clk_users == 1) {
if (TASHA_IS_2_0(tasha->wcd9xxx->version))
- wcd9xxx_reg_update_bits(
- &tasha->wcd9xxx->core_res,
+ regmap_update_bits(
+ tasha->wcd9xxx->regmap,
WCD9335_TEST_DEBUG_NPL_DLY_TEST_1,
0x10, 0x00);
__tasha_cdc_mclk_enable(tasha, true);
- wcd9xxx_reg_update_bits(&tasha->wcd9xxx->core_res,
+ regmap_update_bits(tasha->wcd9xxx->regmap,
WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL,
0x01, 0x01);
}
} else {
tasha->swr_clk_users--;
if (tasha->swr_clk_users == 0) {
- wcd9xxx_reg_update_bits(&tasha->wcd9xxx->core_res,
+ regmap_update_bits(tasha->wcd9xxx->regmap,
WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL,
0x01, 0x00);
__tasha_cdc_mclk_enable(tasha, false);
if (TASHA_IS_2_0(tasha->wcd9xxx->version))
- wcd9xxx_reg_update_bits(
- &tasha->wcd9xxx->core_res,
+ regmap_update_bits(
+ tasha->wcd9xxx->regmap,
WCD9335_TEST_DEBUG_NPL_DLY_TEST_1,
0x10, 0x10);
}
@@ -13243,31 +13443,35 @@ EXPORT_SYMBOL(tasha_codec_ver);
static int __tasha_enable_efuse_sensing(struct tasha_priv *tasha)
{
+ int val, rc;
+
__tasha_cdc_mclk_enable(tasha, true);
- wcd9xxx_reg_update_bits(&tasha->wcd9xxx->core_res,
- WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x20);
- wcd9xxx_reg_update_bits(&tasha->wcd9xxx->core_res,
- WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
+ regmap_update_bits(tasha->wcd9xxx->regmap,
+ WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x20);
+ regmap_update_bits(tasha->wcd9xxx->regmap,
+ WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
/*
* 5ms sleep required after enabling efuse control
* before checking the status.
*/
usleep_range(5000, 5500);
- if (!(wcd9xxx_reg_read(&tasha->wcd9xxx->core_res,
- WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & 0x01))
+ rc = regmap_read(tasha->wcd9xxx->regmap,
+ WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
+
+ if (rc || (!(val & 0x01)))
WARN(1, "%s: Efuse sense is not complete\n", __func__);
__tasha_cdc_mclk_enable(tasha, false);
- return 0;
+ return rc;
}
void tasha_get_codec_ver(struct tasha_priv *tasha)
{
int i;
- u8 val;
+ int val;
struct tasha_reg_mask_val codec_reg[] = {
{WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10, 0xFF, 0xFF},
{WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11, 0xFF, 0x83},
@@ -13276,8 +13480,7 @@ void tasha_get_codec_ver(struct tasha_priv *tasha)
__tasha_enable_efuse_sensing(tasha);
for (i = 0; i < ARRAY_SIZE(codec_reg); i++) {
- val = wcd9xxx_reg_read(&tasha->wcd9xxx->core_res,
- codec_reg[i].reg);
+ regmap_read(tasha->wcd9xxx->regmap, codec_reg[i].reg, &val);
if (!(val && codec_reg[i].val)) {
codec_ver = WCD9335;
goto ret;
diff --git a/sound/soc/codecs/wcd9335.h b/sound/soc/codecs/wcd9335.h
index 40cb70f05280..67280c583b2a 100644
--- a/sound/soc/codecs/wcd9335.h
+++ b/sound/soc/codecs/wcd9335.h
@@ -83,6 +83,44 @@ enum {
TASHA_TX_MAX,
};
+enum {
+ /* INTR_REG 0 */
+ WCD9335_IRQ_FLL_LOCK_LOSS = 1,
+ WCD9335_IRQ_HPH_PA_OCPL_FAULT,
+ WCD9335_IRQ_HPH_PA_OCPR_FAULT,
+ WCD9335_IRQ_EAR_PA_OCP_FAULT,
+ WCD9335_IRQ_HPH_PA_CNPL_COMPLETE,
+ WCD9335_IRQ_HPH_PA_CNPR_COMPLETE,
+ WCD9335_IRQ_EAR_PA_CNP_COMPLETE,
+ /* INTR_REG 1 */
+ WCD9335_IRQ_MBHC_SW_DET,
+ WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
+ WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
+ WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
+ WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ WCD9335_IRQ_RESERVED_0,
+ WCD9335_IRQ_RESERVED_1,
+ WCD9335_IRQ_RESERVED_2,
+ /* INTR_REG 2 */
+ WCD9335_IRQ_LINE_PA1_CNP_COMPLETE,
+ WCD9335_IRQ_LINE_PA2_CNP_COMPLETE,
+ WCD9335_IRQ_LINE_PA3_CNP_COMPLETE,
+ WCD9335_IRQ_LINE_PA4_CNP_COMPLETE,
+ WCD9335_IRQ_SOUNDWIRE,
+ WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE,
+ WCD9335_IRQ_RCO_ERROR,
+ WCD9335_IRQ_SVA_ERROR,
+ /* INTR_REG 3 */
+ WCD9335_IRQ_MAD_AUDIO,
+ WCD9335_IRQ_MAD_BEACON,
+ WCD9335_IRQ_MAD_ULTRASOUND,
+ WCD9335_IRQ_VBAT_ATTACK,
+ WCD9335_IRQ_VBAT_RESTORE,
+ WCD9335_IRQ_SVA_OUTBOX1,
+ WCD9335_IRQ_SVA_OUTBOX2,
+ WCD9335_NUM_IRQS,
+};
+
enum wcd9335_codec_event {
WCD9335_CODEC_EVENT_CODEC_UP = 0,
};
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 168d1d5648be..52ca82fba8e9 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. 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 and
@@ -20,7 +20,7 @@
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
#include <linux/mfd/wcd9xxx/pdata.h>
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index 824758d9859a..9cd9736dc850 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. 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 and
@@ -35,25 +35,41 @@ static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type)
static int wcd_resmgr_codec_reg_update_bits(struct wcd9xxx_resmgr_v2 *resmgr,
u16 reg, u8 mask, u8 val)
{
- int change;
- if (resmgr->codec)
- change = snd_soc_update_bits(resmgr->codec, reg, mask, val);
- else
- change = wcd9xxx_reg_update_bits(resmgr->core_res, reg,
- mask, val);
+ bool change;
+ int ret;
+
+ if (resmgr->codec) {
+ ret = snd_soc_update_bits(resmgr->codec, reg, mask, val);
+ } else if (resmgr->core_res->wcd_core_regmap) {
+ ret = regmap_update_bits_check(
+ resmgr->core_res->wcd_core_regmap,
+ reg, mask, val, &change);
+ if (!ret)
+ ret = change;
+ } else {
+ pr_err("%s: codec/regmap not defined\n", __func__);
+ ret = -EINVAL;
+ }
- return change;
+ return ret;
}
static int wcd_resmgr_codec_reg_read(struct wcd9xxx_resmgr_v2 *resmgr,
unsigned int reg)
{
- int val;
+ int val, ret;
- if (resmgr->codec)
+ if (resmgr->codec) {
val = snd_soc_read(resmgr->codec, reg);
- else
- val = wcd9xxx_reg_read(resmgr->core_res, reg);
+ } else if (resmgr->core_res->wcd_core_regmap) {
+ ret = regmap_read(resmgr->core_res->wcd_core_regmap,
+ reg, &val);
+ if (ret)
+ val = ret;
+ } else {
+ pr_err("%s: wcd regmap is null\n", __func__);
+ return -EINVAL;
+ }
return val;
}
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.h b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
index 5f44e6fdefbf..61e242d52c1e 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. 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 and
@@ -13,7 +13,7 @@
#ifndef __WCD9XXX_COMMON_V2_H__
#define __WCD9XXX_COMMON_V2_H__
-#include <linux/mfd/wcd9xxx/core-resource.h>
+#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
enum wcd_clock_type {
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index a334eadd9918..e35d6161d488 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, 2016 The Linux Foundation. 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 and
@@ -13,7 +13,7 @@
#define __WCD9XXX_COMMON_H__
#include <linux/notifier.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
+#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
enum wcd9xxx_bandgap_type {
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index 58fca9131b3c..b1e105b3153a 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -28,7 +28,7 @@
#include <sound/cpe_err.h>
#include <soc/qcom/pm.h>
#include <linux/mfd/wcd9xxx/core.h>
-#include <linux/mfd/wcd9xxx/core-resource.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h>
#include <sound/audio_cal_utils.h>
#include "wcd_cpe_core.h"
#include "wcd_cpe_services.h"
diff --git a/sound/soc/codecs/wcd_cpe_core.h b/sound/soc/codecs/wcd_cpe_core.h
index 77027d58b178..b09b03d2f81d 100644
--- a/sound/soc/codecs/wcd_cpe_core.h
+++ b/sound/soc/codecs/wcd_cpe_core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2016, The Linux Foundation. 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 and
@@ -10,6 +10,9 @@
* GNU General Public License for more details.
*/
+#ifndef WCD_CPE_CORE_H
+#define WCD_CPE_CORE_H
+
#include <soc/qcom/ramdump.h>
#include <linux/dma-mapping.h>
#include "wcd_cpe_services.h"
@@ -220,3 +223,4 @@ int wcd_cpe_ssr_event(void *core_handle,
enum wcd_cpe_ssr_state_event event);
struct wcd_cpe_core *wcd_cpe_init(const char *,
struct snd_soc_codec *, struct wcd_cpe_params *params);
+#endif