diff options
| author | Sudheer Papothi <spapothi@codeaurora.org> | 2016-03-02 01:56:43 +0530 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:11:25 -0700 |
| commit | be1a516dcb8571becec57f8965ca5abfdf7da092 (patch) | |
| tree | 4f4a5fe235b9e5bef10b5aa764f31f6049a88da2 /sound/soc/msm/msm-audio-pinctrl.c | |
| parent | 26c32e7dad6124d7d726ad17e8c661376cf10d4c (diff) | |
ASoC: msm: Add Audio drivers for MSM targets
Add snapshot for audio drivers for MSM targets. The code is
migrated from msm-3.18 kernel at the below commit/AU level -
AU_LINUX_ANDROID_LA.HB.1.3.1.06.00.00.187.056
(e70ad0cd5efdd9dc91a77dcdac31d6132e1315c1)
(Promotion of kernel.lnx.3.18-151201.)
Signed-off-by: Sudheer Papothi <spapothi@codeaurora.org>
Diffstat (limited to 'sound/soc/msm/msm-audio-pinctrl.c')
| -rw-r--r-- | sound/soc/msm/msm-audio-pinctrl.c | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/sound/soc/msm/msm-audio-pinctrl.c b/sound/soc/msm/msm-audio-pinctrl.c new file mode 100644 index 000000000000..d30b0c40f993 --- /dev/null +++ b/sound/soc/msm/msm-audio-pinctrl.c @@ -0,0 +1,304 @@ + /* Copyright (c) 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. + */ + +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include "msm-audio-pinctrl.h" + +/* + * pinctrl -- handle to query pinctrl apis + * cdc lines -- stores pinctrl handles for pinctrl states + * active_set -- maintain the overall pinctrl state + */ +struct cdc_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state **cdc_lines; + int active_set; +}; + +/* + * gpiosets -- stores all gpiosets mentioned in dtsi file + * gpiosets_comb_names -- stores all possible gpioset combinations + * gpioset_state -- maintains counter for each gpioset + * gpiosets_max -- maintain the total supported gpiosets + * gpiosets_comb_max -- maintain the total gpiosets combinations + */ +struct cdc_gpioset_info { + char **gpiosets; + char **gpiosets_comb_names; + uint8_t *gpioset_state; + int gpiosets_max; + int gpiosets_comb_max; +}; + +static struct cdc_pinctrl_info pinctrl_info[MAX_PINCTRL_CLIENT]; +static struct cdc_gpioset_info gpioset_info[MAX_PINCTRL_CLIENT]; + +/* Finds the index for the gpio set in the dtsi file */ +int msm_get_gpioset_index(enum pinctrl_client client, char *keyword) +{ + int i; + + for (i = 0; i < gpioset_info[client].gpiosets_max; i++) { + if (!(strcmp(gpioset_info[client].gpiosets[i], keyword))) + break; + } + /* Checking if the keyword is present in dtsi or not */ + if (i != gpioset_info[client].gpiosets_max) + return i; + else + return -EINVAL; +} + +/* + * This function reads the following from dtsi file + * 1. All gpio sets + * 2. All combinations of gpio sets + * 3. Pinctrl handles to gpio sets + * + * Returns error if there is + * 1. Problem reading from dtsi file + * 2. Memory allocation failure + */ +int msm_gpioset_initialize(enum pinctrl_client client, + struct device *dev) +{ + struct pinctrl *pinctrl; + const char *gpioset_names = "qcom,msm-gpios"; + const char *gpioset_combinations = "qcom,pinctrl-names"; + const char *gpioset_names_str = NULL; + const char *gpioset_comb_str = NULL; + int num_strings = 0; + int ret = 0; + int i = 0; + + pr_debug("%s\n", __func__); + pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(pinctrl)) { + pr_err("%s: Unable to get pinctrl handle\n", + __func__); + return -EINVAL; + } + pinctrl_info[client].pinctrl = pinctrl; + + /* Reading of gpio sets */ + num_strings = of_property_count_strings(dev->of_node, + gpioset_names); + if (num_strings < 0) { + dev_err(dev, + "%s: missing %s in dt node or length is incorrect\n", + __func__, gpioset_names); + goto err; + } + gpioset_info[client].gpiosets_max = num_strings; + gpioset_info[client].gpiosets = devm_kzalloc(dev, + gpioset_info[client].gpiosets_max * + sizeof(char *), GFP_KERNEL); + if (!gpioset_info[client].gpiosets) { + dev_err(dev, "Can't allocate memory for gpio set names\n"); + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < num_strings; i++) { + ret = of_property_read_string_index(dev->of_node, + gpioset_names, i, &gpioset_names_str); + + gpioset_info[client].gpiosets[i] = devm_kzalloc(dev, + (strlen(gpioset_names_str) + 1), GFP_KERNEL); + + if (!gpioset_info[client].gpiosets[i]) { + dev_err(dev, "%s: Can't allocate gpiosets[%d] data\n", + __func__, i); + ret = -ENOMEM; + goto err; + } + strlcpy(gpioset_info[client].gpiosets[i], + gpioset_names_str, strlen(gpioset_names_str)+1); + gpioset_names_str = NULL; + } + num_strings = 0; + + /* Allocating memory for gpio set counter */ + gpioset_info[client].gpioset_state = devm_kzalloc(dev, + gpioset_info[client].gpiosets_max * + sizeof(uint8_t), GFP_KERNEL); + if (!gpioset_info[client].gpioset_state) { + dev_err(dev, "Can't allocate memory for gpio set counter\n"); + ret = -ENOMEM; + goto err; + } + + /* Reading of all combinations of gpio sets */ + num_strings = of_property_count_strings(dev->of_node, + gpioset_combinations); + if (num_strings < 0) { + dev_err(dev, + "%s: missing %s in dt node or length is incorrect\n", + __func__, gpioset_combinations); + goto err; + } + gpioset_info[client].gpiosets_comb_max = num_strings; + gpioset_info[client].gpiosets_comb_names = devm_kzalloc(dev, + num_strings * sizeof(char *), GFP_KERNEL); + if (!gpioset_info[client].gpiosets_comb_names) { + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) { + ret = of_property_read_string_index(dev->of_node, + gpioset_combinations, i, &gpioset_comb_str); + + gpioset_info[client].gpiosets_comb_names[i] = devm_kzalloc(dev, + (strlen(gpioset_comb_str) + 1), GFP_KERNEL); + if (!gpioset_info[client].gpiosets_comb_names[i]) { + ret = -ENOMEM; + goto err; + } + + strlcpy(gpioset_info[client].gpiosets_comb_names[i], + gpioset_comb_str, + strlen(gpioset_comb_str)+1); + pr_debug("%s: GPIO configuration %s\n", + __func__, + gpioset_info[client].gpiosets_comb_names[i]); + gpioset_comb_str = NULL; + } + + /* Allocating memory for handles to pinctrl states */ + pinctrl_info[client].cdc_lines = devm_kzalloc(dev, + num_strings * sizeof(char *), GFP_KERNEL); + if (!pinctrl_info[client].cdc_lines) { + ret = -ENOMEM; + goto err; + } + + /* Get pinctrl handles for gpio sets in dtsi file */ + for (i = 0; i < num_strings; i++) { + pinctrl_info[client].cdc_lines[i] = pinctrl_lookup_state( + pinctrl, + (const char *)gpioset_info[client]. + gpiosets_comb_names[i]); + if (IS_ERR(pinctrl_info[client].cdc_lines[i])) + pr_err("%s: Unable to get pinctrl handle for %s\n", + __func__, gpioset_info[client]. + gpiosets_comb_names[i]); + } + goto success; + +err: + /* Free up memory allocated for gpio set combinations */ + for (i = 0; i < gpioset_info[client].gpiosets_max; i++) { + if (NULL != gpioset_info[client].gpiosets[i]) + devm_kfree(dev, gpioset_info[client].gpiosets[i]); + } + if (NULL != gpioset_info[client].gpiosets) + devm_kfree(dev, gpioset_info[client].gpiosets); + + /* Free up memory allocated for gpio set combinations */ + for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) { + if (NULL != gpioset_info[client].gpiosets_comb_names[i]) + devm_kfree(dev, + gpioset_info[client].gpiosets_comb_names[i]); + } + if (NULL != gpioset_info[client].gpiosets_comb_names) + devm_kfree(dev, gpioset_info[client].gpiosets_comb_names); + + /* Free up memory allocated for handles to pinctrl states */ + if (NULL != pinctrl_info[client].cdc_lines) + devm_kfree(dev, pinctrl_info[client].cdc_lines); + + /* Free up memory allocated for counter of gpio sets */ + if (NULL != gpioset_info[client].gpioset_state) + devm_kfree(dev, gpioset_info[client].gpioset_state); + +success: + return ret; +} + +int msm_gpioset_activate(enum pinctrl_client client, char *keyword) +{ + int ret = 0; + int gp_set = 0; + int active_set = 0; + + gp_set = msm_get_gpioset_index(client, keyword); + if (gp_set < 0) { + pr_err("%s: gpio set name does not exist\n", + __func__); + return gp_set; + } + + if (!gpioset_info[client].gpioset_state[gp_set]) { + /* + * If pinctrl pointer is not valid, + * no need to proceed further + */ + active_set = pinctrl_info[client].active_set; + if (IS_ERR(pinctrl_info[client].cdc_lines[active_set])) + return 0; + + pinctrl_info[client].active_set |= (1 << gp_set); + active_set = pinctrl_info[client].active_set; + pr_debug("%s: pinctrl.active_set: %d\n", __func__, active_set); + + /* Select the appropriate pinctrl state */ + ret = pinctrl_select_state(pinctrl_info[client].pinctrl, + pinctrl_info[client].cdc_lines[active_set]); + } + gpioset_info[client].gpioset_state[gp_set]++; + + return ret; +} + +int msm_gpioset_suspend(enum pinctrl_client client, char *keyword) +{ + int ret = 0; + int gp_set = 0; + int active_set = 0; + + gp_set = msm_get_gpioset_index(client, keyword); + if (gp_set < 0) { + pr_err("%s: gpio set name does not exist\n", + __func__); + return gp_set; + } + + if (1 == gpioset_info[client].gpioset_state[gp_set]) { + pinctrl_info[client].active_set &= ~(1 << gp_set); + /* + * If pinctrl pointer is not valid, + * no need to proceed further + */ + active_set = pinctrl_info[client].active_set; + if (IS_ERR(pinctrl_info[client].cdc_lines[active_set])) + return -EINVAL; + + pr_debug("%s: pinctrl.active_set: %d\n", __func__, + pinctrl_info[client].active_set); + /* Select the appropriate pinctrl state */ + ret = pinctrl_select_state(pinctrl_info[client].pinctrl, + pinctrl_info[client].cdc_lines[pinctrl_info[client]. + active_set]); + } + if (!(gpioset_info[client].gpioset_state[gp_set])) { + pr_err("%s: Invalid call to de activate gpios: %d\n", __func__, + gpioset_info[client].gpioset_state[gp_set]); + return -EINVAL; + } + + gpioset_info[client].gpioset_state[gp_set]--; + + return ret; +} |
