diff options
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, ®); + 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, ®); - 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, ®map_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, ®map_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, ®map_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 *)®); + ret = regmap_bulk_write(wcd9xxx->regmap, swr_rd_addr_base, + (u8 *)®, 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 |