summaryrefslogtreecommitdiff
path: root/sound/soc/msm/msm-audio-pinctrl.c
diff options
context:
space:
mode:
authorSudheer Papothi <spapothi@codeaurora.org>2016-03-02 01:56:43 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:11:25 -0700
commitbe1a516dcb8571becec57f8965ca5abfdf7da092 (patch)
tree4f4a5fe235b9e5bef10b5aa764f31f6049a88da2 /sound/soc/msm/msm-audio-pinctrl.c
parent26c32e7dad6124d7d726ad17e8c661376cf10d4c (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.c304
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;
+}