All of lore.kernel.org
 help / color / mirror / Atom feed
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
To: robh@kernel.org, broonie@kernel.org, lee.jones@linaro.org,
	linus.walleij@linaro.org
Cc: vinod.koul@linaro.org, alsa-devel@alsa-project.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	spapothi@codeaurora.org, bgoswami@codeaurora.org,
	linux-gpio@vger.kernel.org,
	Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>,
	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Subject: [PATCH v3 09/11] pinctrl: qcom-wcd934x: Add support to wcd934x pinctrl driver.
Date: Tue, 29 Oct 2019 11:26:58 +0000	[thread overview]
Message-ID: <20191029112700.14548-10-srinivas.kandagatla@linaro.org> (raw)
In-Reply-To: <20191029112700.14548-1-srinivas.kandagatla@linaro.org>

From: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>

This patch adds support to wcd934x pinctrl block found in
WCD9340/WC9341 Audio codecs.

[Srini: multiple cleanups to the code]
Signed-off-by: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/pinctrl/qcom/Kconfig                |   7 +
 drivers/pinctrl/qcom/Makefile               |   1 +
 drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c | 365 ++++++++++++++++++++
 3 files changed, 373 insertions(+)
 create mode 100644 drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c

diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 32fc2458b8eb..7406df5fb89a 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -195,4 +195,11 @@ config PINCTRL_SM8150
          Qualcomm Technologies Inc TLMM block found on the Qualcomm
          Technologies Inc SM8150 platform.
 
+config PINCTRL_WCD934X
+	tristate "Qualcomm Technologies Inc WCD9340/WCD9341 pin controller driver"
+	depends on GPIOLIB && OF
+	help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm Technologies Inc Pinctrl block found on the Qualcomm
+         Technologies Inc WCD9340/WCD9341 Audio Codec.
 endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index f8bb0c265381..8c42ba1bdd69 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_PINCTRL_SC7180)	+= pinctrl-sc7180.o
 obj-$(CONFIG_PINCTRL_SDM660)   += pinctrl-sdm660.o
 obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
 obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
+obj-$(CONFIG_PINCTRL_WCD934X) += pinctrl-wcd934x-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c b/drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c
new file mode 100644
index 000000000000..1aff88d0bcb3
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2019, Linaro Limited
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define WCD_REG_DIR_CTL_OFFSET 0x42
+#define WCD_REG_VAL_CTL_OFFSET 0x43
+#define WCD_GPIO_PULL_UP       1
+#define WCD_GPIO_PULL_DOWN     2
+#define WCD_GPIO_BIAS_DISABLE  3
+#define WCD_GPIO_STRING_LEN    20
+#define WCD934X_NPINS		5
+
+/**
+ * struct wcd_gpio_pad - keep current GPIO settings
+ * @offset: offset of gpio.
+ * @is_valid: Set to false, when GPIO in high Z state.
+ * @value: value of a pin
+ * @output_enabled: Set to true if GPIO is output and false if it is input
+ * @pullup: Constant current which flow through GPIO output buffer.
+ * @strength: Drive strength of a pin
+ */
+struct wcd_gpio_pad {
+	u16  offset;
+	bool is_valid;
+	bool value;
+	bool output_enabled;
+	unsigned int pullup;
+	unsigned int strength;
+};
+
+struct wcd_gpio_priv {
+	struct device *dev;
+	struct regmap *map;
+	struct pinctrl_dev *ctrl;
+	struct gpio_chip chip;
+};
+
+static int wcd_gpio_read(struct wcd_gpio_priv *priv_data,
+			 struct wcd_gpio_pad *pad, unsigned int addr)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(priv_data->map, addr, &val);
+	if (ret < 0)
+		dev_err(priv_data->dev, "%s: read 0x%x failed\n",
+			__func__, addr);
+	else
+		ret = (val >> pad->offset);
+
+	return ret;
+}
+
+static int wcd_gpio_write(struct wcd_gpio_priv *priv_data,
+			  struct wcd_gpio_pad *pad, unsigned int addr,
+			  unsigned int val)
+{
+	int ret;
+
+	ret = regmap_update_bits(priv_data->map, addr, (1 << pad->offset),
+				 val << pad->offset);
+	if (ret < 0)
+		dev_err(priv_data->dev, "write 0x%x failed\n", addr);
+
+	return ret;
+}
+
+static int wcd_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	return pctldev->desc->npins;
+}
+
+static const char *wcd_get_group_name(struct pinctrl_dev *pctldev,
+				      unsigned int pin)
+{
+	return pctldev->desc->pins[pin].name;
+}
+
+static int wcd_get_group_pins(struct pinctrl_dev *pctldev, unsigned int pin,
+			      const unsigned int **pins, unsigned int *num_pins)
+{
+	*pins = &pctldev->desc->pins[pin].number;
+	*num_pins = 1;
+
+	return 0;
+}
+
+static const struct pinctrl_ops wcd_pinctrl_ops = {
+	.get_groups_count       = wcd_get_groups_count,
+	.get_group_name         = wcd_get_group_name,
+	.get_group_pins         = wcd_get_group_pins,
+	.dt_node_to_map         = pinconf_generic_dt_node_to_map_group,
+	.dt_free_map            = pinctrl_utils_free_map,
+};
+
+static int wcd_config_get(struct pinctrl_dev *pctldev,
+			  unsigned int pin, unsigned long *config)
+{
+	unsigned int param = pinconf_to_config_param(*config);
+	struct wcd_gpio_pad *pad;
+	unsigned int arg;
+
+	pad = pctldev->desc->pins[pin].drv_data;
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		arg = pad->pullup == WCD_GPIO_PULL_DOWN;
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		arg = pad->pullup = WCD_GPIO_BIAS_DISABLE;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		arg = pad->pullup == WCD_GPIO_PULL_UP;
+		break;
+	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+		arg = !pad->is_valid;
+		break;
+	case PIN_CONFIG_INPUT_ENABLE:
+		arg = pad->output_enabled;
+		break;
+	case PIN_CONFIG_OUTPUT:
+		arg = pad->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*config = pinconf_to_config_packed(param, arg);
+	return 0;
+}
+
+static int wcd_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+			  unsigned long *configs, unsigned int nconfs)
+{
+	struct wcd_gpio_priv *priv_data = pinctrl_dev_get_drvdata(pctldev);
+	struct wcd_gpio_pad *pad;
+	unsigned int param, arg;
+	int i, ret;
+
+	pad = pctldev->desc->pins[pin].drv_data;
+
+	for (i = 0; i < nconfs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
+
+		switch (param) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			pad->pullup = WCD_GPIO_BIAS_DISABLE;
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			pad->pullup = WCD_GPIO_PULL_UP;
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			pad->pullup = WCD_GPIO_PULL_DOWN;
+			break;
+		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+			pad->is_valid = false;
+			break;
+		case PIN_CONFIG_INPUT_ENABLE:
+			pad->output_enabled = false;
+			break;
+		case PIN_CONFIG_OUTPUT:
+			pad->output_enabled = true;
+			pad->value = arg;
+			break;
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			pad->strength = arg;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	ret = wcd_gpio_write(priv_data, pad, WCD_REG_DIR_CTL_OFFSET,
+			     pad->output_enabled);
+	if (ret < 0)
+		return ret;
+
+	if (pad->output_enabled)
+		ret = wcd_gpio_write(priv_data, pad, WCD_REG_VAL_CTL_OFFSET,
+				     pad->value);
+
+	return ret;
+}
+
+static const struct pinconf_ops wcd_pinconf_ops = {
+	.is_generic  = true,
+	.pin_config_group_get = wcd_config_get,
+	.pin_config_group_set = wcd_config_set,
+};
+
+static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
+
+	return wcd_config_set(priv_data->ctrl, pin, &config, 1);
+}
+
+static int wcd_gpio_direction_output(struct gpio_chip *chip,
+				      unsigned int pin, int val)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
+
+	return wcd_config_set(priv_data->ctrl, pin, &config, 1);
+}
+
+static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	struct wcd_gpio_pad *pad;
+	int value;
+
+	pad = priv_data->ctrl->desc->pins[pin].drv_data;
+
+	if (!pad->is_valid)
+		return -EINVAL;
+
+	value = wcd_gpio_read(priv_data, pad, WCD_REG_VAL_CTL_OFFSET);
+
+	return value;
+}
+
+static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
+
+	wcd_config_set(priv_data->ctrl, pin, &config, 1);
+}
+
+static const struct gpio_chip wcd_gpio_chip = {
+	.direction_input  = wcd_gpio_direction_input,
+	.direction_output = wcd_gpio_direction_output,
+	.get = wcd_gpio_get,
+	.set = wcd_gpio_set,
+};
+
+static int wcd_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pinctrl_pin_desc *pindesc;
+	struct pinctrl_desc *pctrldesc;
+	struct wcd_gpio_pad *pad, *pads;
+	struct wcd_gpio_priv *priv_data;
+	u32 npins = WCD934X_NPINS;
+	char **name;
+	int i;
+
+	priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL);
+	if (!priv_data)
+		return -ENOMEM;
+
+	priv_data->dev = dev;
+	priv_data->map = dev_get_regmap(dev->parent, NULL);
+	if (!priv_data->map) {
+		dev_err(dev, "%s: failed to get regmap\n", __func__);
+		return  -EINVAL;
+	}
+
+	pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
+	if (!pindesc)
+		return -ENOMEM;
+
+	pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
+	if (!pads)
+		return -ENOMEM;
+
+	pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
+	if (!pctrldesc)
+		return -ENOMEM;
+
+	pctrldesc->pctlops = &wcd_pinctrl_ops;
+	pctrldesc->confops = &wcd_pinconf_ops;
+	pctrldesc->owner = THIS_MODULE;
+	pctrldesc->name = dev_name(dev);
+	pctrldesc->pins = pindesc;
+	pctrldesc->npins = npins;
+
+	name = devm_kcalloc(dev, npins, sizeof(char *), GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	for (i = 0; i < npins; i++, pindesc++) {
+		name[i] = devm_kzalloc(dev, sizeof(char) * WCD_GPIO_STRING_LEN,
+				       GFP_KERNEL);
+		if (!name[i])
+			return -ENOMEM;
+
+		pad = &pads[i];
+		pindesc->drv_data = pad;
+		pindesc->number = i;
+		snprintf(name[i], (WCD_GPIO_STRING_LEN - 1), "gpio%d", (i+1));
+		pindesc->name = name[i];
+		pad->offset = i;
+		pad->is_valid  = true;
+	}
+
+	priv_data->chip = wcd_gpio_chip;
+	priv_data->chip.parent = dev;
+	priv_data->chip.base = -1;
+	priv_data->chip.ngpio = npins;
+	priv_data->chip.label = dev_name(dev);
+	priv_data->chip.of_gpio_n_cells = 2;
+	priv_data->chip.can_sleep = false;
+	platform_set_drvdata(pdev, priv_data);
+
+	priv_data->ctrl = devm_pinctrl_register(dev, pctrldesc, priv_data);
+	if (IS_ERR(priv_data->ctrl)) {
+		dev_err(dev, "%s: failed to register to pinctrl\n", __func__);
+		return PTR_ERR(priv_data->ctrl);
+	}
+
+	return gpiochip_add_data(&priv_data->chip, priv_data);
+}
+
+static int wcd_pinctrl_remove(struct platform_device *pdev)
+{
+	struct wcd_gpio_priv *priv_data = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&priv_data->chip);
+
+	return 0;
+}
+
+static const struct of_device_id wcd_pinctrl_of_match[] = {
+	{ .compatible = "qcom,wcd9340-pinctrl" },
+	{ .compatible = "qcom,wcd9341-pinctrl" },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, wcd_pinctrl_of_match);
+
+static struct platform_driver wcd_pinctrl_driver = {
+	.driver = {
+		   .name = "wcd934x-pinctrl",
+		   .of_match_table = wcd_pinctrl_of_match,
+	},
+	.probe = wcd_pinctrl_probe,
+	.remove = wcd_pinctrl_remove,
+};
+
+module_platform_driver(wcd_pinctrl_driver);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO pin control driver");
+MODULE_LICENSE("GPL v2");
-- 
2.21.0


WARNING: multiple messages have this Message-ID (diff)
From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
To: robh@kernel.org, broonie@kernel.org, lee.jones@linaro.org,
	linus.walleij@linaro.org
Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org,
	bgoswami@codeaurora.org, vinod.koul@linaro.org,
	spapothi@codeaurora.org, linux-kernel@vger.kernel.org,
	Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>,
	linux-gpio@vger.kernel.org,
	Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Subject: [alsa-devel] [PATCH v3 09/11] pinctrl: qcom-wcd934x: Add support to wcd934x pinctrl driver.
Date: Tue, 29 Oct 2019 11:26:58 +0000	[thread overview]
Message-ID: <20191029112700.14548-10-srinivas.kandagatla@linaro.org> (raw)
In-Reply-To: <20191029112700.14548-1-srinivas.kandagatla@linaro.org>

From: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>

This patch adds support to wcd934x pinctrl block found in
WCD9340/WC9341 Audio codecs.

[Srini: multiple cleanups to the code]
Signed-off-by: Yeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/pinctrl/qcom/Kconfig                |   7 +
 drivers/pinctrl/qcom/Makefile               |   1 +
 drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c | 365 ++++++++++++++++++++
 3 files changed, 373 insertions(+)
 create mode 100644 drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c

diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 32fc2458b8eb..7406df5fb89a 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -195,4 +195,11 @@ config PINCTRL_SM8150
          Qualcomm Technologies Inc TLMM block found on the Qualcomm
          Technologies Inc SM8150 platform.
 
+config PINCTRL_WCD934X
+	tristate "Qualcomm Technologies Inc WCD9340/WCD9341 pin controller driver"
+	depends on GPIOLIB && OF
+	help
+         This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+         Qualcomm Technologies Inc Pinctrl block found on the Qualcomm
+         Technologies Inc WCD9340/WCD9341 Audio Codec.
 endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index f8bb0c265381..8c42ba1bdd69 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_PINCTRL_SC7180)	+= pinctrl-sc7180.o
 obj-$(CONFIG_PINCTRL_SDM660)   += pinctrl-sdm660.o
 obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
 obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o
+obj-$(CONFIG_PINCTRL_WCD934X) += pinctrl-wcd934x-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c b/drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c
new file mode 100644
index 000000000000..1aff88d0bcb3
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-wcd934x-gpio.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2019, Linaro Limited
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define WCD_REG_DIR_CTL_OFFSET 0x42
+#define WCD_REG_VAL_CTL_OFFSET 0x43
+#define WCD_GPIO_PULL_UP       1
+#define WCD_GPIO_PULL_DOWN     2
+#define WCD_GPIO_BIAS_DISABLE  3
+#define WCD_GPIO_STRING_LEN    20
+#define WCD934X_NPINS		5
+
+/**
+ * struct wcd_gpio_pad - keep current GPIO settings
+ * @offset: offset of gpio.
+ * @is_valid: Set to false, when GPIO in high Z state.
+ * @value: value of a pin
+ * @output_enabled: Set to true if GPIO is output and false if it is input
+ * @pullup: Constant current which flow through GPIO output buffer.
+ * @strength: Drive strength of a pin
+ */
+struct wcd_gpio_pad {
+	u16  offset;
+	bool is_valid;
+	bool value;
+	bool output_enabled;
+	unsigned int pullup;
+	unsigned int strength;
+};
+
+struct wcd_gpio_priv {
+	struct device *dev;
+	struct regmap *map;
+	struct pinctrl_dev *ctrl;
+	struct gpio_chip chip;
+};
+
+static int wcd_gpio_read(struct wcd_gpio_priv *priv_data,
+			 struct wcd_gpio_pad *pad, unsigned int addr)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(priv_data->map, addr, &val);
+	if (ret < 0)
+		dev_err(priv_data->dev, "%s: read 0x%x failed\n",
+			__func__, addr);
+	else
+		ret = (val >> pad->offset);
+
+	return ret;
+}
+
+static int wcd_gpio_write(struct wcd_gpio_priv *priv_data,
+			  struct wcd_gpio_pad *pad, unsigned int addr,
+			  unsigned int val)
+{
+	int ret;
+
+	ret = regmap_update_bits(priv_data->map, addr, (1 << pad->offset),
+				 val << pad->offset);
+	if (ret < 0)
+		dev_err(priv_data->dev, "write 0x%x failed\n", addr);
+
+	return ret;
+}
+
+static int wcd_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	return pctldev->desc->npins;
+}
+
+static const char *wcd_get_group_name(struct pinctrl_dev *pctldev,
+				      unsigned int pin)
+{
+	return pctldev->desc->pins[pin].name;
+}
+
+static int wcd_get_group_pins(struct pinctrl_dev *pctldev, unsigned int pin,
+			      const unsigned int **pins, unsigned int *num_pins)
+{
+	*pins = &pctldev->desc->pins[pin].number;
+	*num_pins = 1;
+
+	return 0;
+}
+
+static const struct pinctrl_ops wcd_pinctrl_ops = {
+	.get_groups_count       = wcd_get_groups_count,
+	.get_group_name         = wcd_get_group_name,
+	.get_group_pins         = wcd_get_group_pins,
+	.dt_node_to_map         = pinconf_generic_dt_node_to_map_group,
+	.dt_free_map            = pinctrl_utils_free_map,
+};
+
+static int wcd_config_get(struct pinctrl_dev *pctldev,
+			  unsigned int pin, unsigned long *config)
+{
+	unsigned int param = pinconf_to_config_param(*config);
+	struct wcd_gpio_pad *pad;
+	unsigned int arg;
+
+	pad = pctldev->desc->pins[pin].drv_data;
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		arg = pad->pullup == WCD_GPIO_PULL_DOWN;
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		arg = pad->pullup = WCD_GPIO_BIAS_DISABLE;
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		arg = pad->pullup == WCD_GPIO_PULL_UP;
+		break;
+	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+		arg = !pad->is_valid;
+		break;
+	case PIN_CONFIG_INPUT_ENABLE:
+		arg = pad->output_enabled;
+		break;
+	case PIN_CONFIG_OUTPUT:
+		arg = pad->value;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*config = pinconf_to_config_packed(param, arg);
+	return 0;
+}
+
+static int wcd_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+			  unsigned long *configs, unsigned int nconfs)
+{
+	struct wcd_gpio_priv *priv_data = pinctrl_dev_get_drvdata(pctldev);
+	struct wcd_gpio_pad *pad;
+	unsigned int param, arg;
+	int i, ret;
+
+	pad = pctldev->desc->pins[pin].drv_data;
+
+	for (i = 0; i < nconfs; i++) {
+		param = pinconf_to_config_param(configs[i]);
+		arg = pinconf_to_config_argument(configs[i]);
+
+		switch (param) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			pad->pullup = WCD_GPIO_BIAS_DISABLE;
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			pad->pullup = WCD_GPIO_PULL_UP;
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			pad->pullup = WCD_GPIO_PULL_DOWN;
+			break;
+		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+			pad->is_valid = false;
+			break;
+		case PIN_CONFIG_INPUT_ENABLE:
+			pad->output_enabled = false;
+			break;
+		case PIN_CONFIG_OUTPUT:
+			pad->output_enabled = true;
+			pad->value = arg;
+			break;
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			pad->strength = arg;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	ret = wcd_gpio_write(priv_data, pad, WCD_REG_DIR_CTL_OFFSET,
+			     pad->output_enabled);
+	if (ret < 0)
+		return ret;
+
+	if (pad->output_enabled)
+		ret = wcd_gpio_write(priv_data, pad, WCD_REG_VAL_CTL_OFFSET,
+				     pad->value);
+
+	return ret;
+}
+
+static const struct pinconf_ops wcd_pinconf_ops = {
+	.is_generic  = true,
+	.pin_config_group_get = wcd_config_get,
+	.pin_config_group_set = wcd_config_set,
+};
+
+static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
+
+	return wcd_config_set(priv_data->ctrl, pin, &config, 1);
+}
+
+static int wcd_gpio_direction_output(struct gpio_chip *chip,
+				      unsigned int pin, int val)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
+
+	return wcd_config_set(priv_data->ctrl, pin, &config, 1);
+}
+
+static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	struct wcd_gpio_pad *pad;
+	int value;
+
+	pad = priv_data->ctrl->desc->pins[pin].drv_data;
+
+	if (!pad->is_valid)
+		return -EINVAL;
+
+	value = wcd_gpio_read(priv_data, pad, WCD_REG_VAL_CTL_OFFSET);
+
+	return value;
+}
+
+static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
+{
+	struct wcd_gpio_priv *priv_data = gpiochip_get_data(chip);
+	unsigned long config;
+
+	config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
+
+	wcd_config_set(priv_data->ctrl, pin, &config, 1);
+}
+
+static const struct gpio_chip wcd_gpio_chip = {
+	.direction_input  = wcd_gpio_direction_input,
+	.direction_output = wcd_gpio_direction_output,
+	.get = wcd_gpio_get,
+	.set = wcd_gpio_set,
+};
+
+static int wcd_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct pinctrl_pin_desc *pindesc;
+	struct pinctrl_desc *pctrldesc;
+	struct wcd_gpio_pad *pad, *pads;
+	struct wcd_gpio_priv *priv_data;
+	u32 npins = WCD934X_NPINS;
+	char **name;
+	int i;
+
+	priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL);
+	if (!priv_data)
+		return -ENOMEM;
+
+	priv_data->dev = dev;
+	priv_data->map = dev_get_regmap(dev->parent, NULL);
+	if (!priv_data->map) {
+		dev_err(dev, "%s: failed to get regmap\n", __func__);
+		return  -EINVAL;
+	}
+
+	pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
+	if (!pindesc)
+		return -ENOMEM;
+
+	pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
+	if (!pads)
+		return -ENOMEM;
+
+	pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
+	if (!pctrldesc)
+		return -ENOMEM;
+
+	pctrldesc->pctlops = &wcd_pinctrl_ops;
+	pctrldesc->confops = &wcd_pinconf_ops;
+	pctrldesc->owner = THIS_MODULE;
+	pctrldesc->name = dev_name(dev);
+	pctrldesc->pins = pindesc;
+	pctrldesc->npins = npins;
+
+	name = devm_kcalloc(dev, npins, sizeof(char *), GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	for (i = 0; i < npins; i++, pindesc++) {
+		name[i] = devm_kzalloc(dev, sizeof(char) * WCD_GPIO_STRING_LEN,
+				       GFP_KERNEL);
+		if (!name[i])
+			return -ENOMEM;
+
+		pad = &pads[i];
+		pindesc->drv_data = pad;
+		pindesc->number = i;
+		snprintf(name[i], (WCD_GPIO_STRING_LEN - 1), "gpio%d", (i+1));
+		pindesc->name = name[i];
+		pad->offset = i;
+		pad->is_valid  = true;
+	}
+
+	priv_data->chip = wcd_gpio_chip;
+	priv_data->chip.parent = dev;
+	priv_data->chip.base = -1;
+	priv_data->chip.ngpio = npins;
+	priv_data->chip.label = dev_name(dev);
+	priv_data->chip.of_gpio_n_cells = 2;
+	priv_data->chip.can_sleep = false;
+	platform_set_drvdata(pdev, priv_data);
+
+	priv_data->ctrl = devm_pinctrl_register(dev, pctrldesc, priv_data);
+	if (IS_ERR(priv_data->ctrl)) {
+		dev_err(dev, "%s: failed to register to pinctrl\n", __func__);
+		return PTR_ERR(priv_data->ctrl);
+	}
+
+	return gpiochip_add_data(&priv_data->chip, priv_data);
+}
+
+static int wcd_pinctrl_remove(struct platform_device *pdev)
+{
+	struct wcd_gpio_priv *priv_data = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&priv_data->chip);
+
+	return 0;
+}
+
+static const struct of_device_id wcd_pinctrl_of_match[] = {
+	{ .compatible = "qcom,wcd9340-pinctrl" },
+	{ .compatible = "qcom,wcd9341-pinctrl" },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, wcd_pinctrl_of_match);
+
+static struct platform_driver wcd_pinctrl_driver = {
+	.driver = {
+		   .name = "wcd934x-pinctrl",
+		   .of_match_table = wcd_pinctrl_of_match,
+	},
+	.probe = wcd_pinctrl_probe,
+	.remove = wcd_pinctrl_remove,
+};
+
+module_platform_driver(wcd_pinctrl_driver);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO pin control driver");
+MODULE_LICENSE("GPL v2");
-- 
2.21.0

_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

  parent reply	other threads:[~2019-10-29 11:29 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-29 11:26 [PATCH v3 00/11] ASoC: Add support to WCD9340/WCD9341 codec Srinivas Kandagatla
2019-10-29 11:26 ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:26 ` [PATCH v3 01/11] ASoC: dt-bindings: add dt bindings for WCD9340/WCD9341 audio codec Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-11-05 19:31   ` Rob Herring
2019-11-05 19:31     ` [alsa-devel] " Rob Herring
2019-11-06 10:08     ` Srinivas Kandagatla
2019-11-06 10:08       ` [alsa-devel] " Srinivas Kandagatla
2019-11-07 17:40       ` Rob Herring
2019-11-07 17:40         ` [alsa-devel] " Rob Herring
2019-10-29 11:26 ` [PATCH v3 02/11] mfd: wcd934x: add support to wcd9340/wcd9341 codec Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-11-11 11:18   ` Lee Jones
2019-11-11 11:18     ` [alsa-devel] " Lee Jones
2019-11-11 12:48     ` Srinivas Kandagatla
2019-11-11 12:48       ` [alsa-devel] " Srinivas Kandagatla
2019-11-11 13:36       ` Lee Jones
2019-11-11 13:36         ` [alsa-devel] " Lee Jones
2019-10-29 11:26 ` [PATCH v3 03/11] ASoC: " Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:26 ` [PATCH v3 04/11] ASoC: wcd934x: add basic controls Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:26 ` [PATCH v3 05/11] ASoC: wcd934x: add playback dapm widgets Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:26 ` [PATCH v3 06/11] ASoC: wcd934x: add capture " Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:26 ` [PATCH v3 07/11] ASoC: wcd934x: add audio routings Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:26 ` [PATCH v3 08/11] dt-bindings: pinctrl: qcom-wcd934x: Add bindings for gpio Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-11-03 23:19   ` Linus Walleij
2019-11-03 23:19     ` [alsa-devel] " Linus Walleij
2019-11-04  9:35     ` Srinivas Kandagatla
2019-11-04  9:35       ` [alsa-devel] " Srinivas Kandagatla
2019-11-05 13:25       ` Linus Walleij
2019-11-05 13:25         ` [alsa-devel] " Linus Walleij
2019-11-05 13:27         ` Srinivas Kandagatla
2019-11-05 13:27           ` [alsa-devel] " Srinivas Kandagatla
2019-11-05 18:49           ` Rob Herring
2019-11-05 18:49             ` [alsa-devel] " Rob Herring
2019-10-29 11:26 ` Srinivas Kandagatla [this message]
2019-10-29 11:26   ` [alsa-devel] [PATCH v3 09/11] pinctrl: qcom-wcd934x: Add support to wcd934x pinctrl driver Srinivas Kandagatla
2019-10-30 14:50   ` Stephen Boyd
2019-10-30 14:50     ` [alsa-devel] " Stephen Boyd
2019-10-31 10:31     ` Srinivas Kandagatla
2019-10-31 10:31       ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:26 ` [PATCH v3 10/11] ASoC: qcom: dt-bindings: Add compatible for DB845c and Lenovo Yoga Srinivas Kandagatla
2019-10-29 11:26   ` [alsa-devel] " Srinivas Kandagatla
2019-10-29 11:27 ` [PATCH v3 11/11] ASoC: qcom: sdm845: add support to " Srinivas Kandagatla
2019-10-29 11:27   ` [alsa-devel] " Srinivas Kandagatla

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191029112700.14548-10-srinivas.kandagatla@linaro.org \
    --to=srinivas.kandagatla@linaro.org \
    --cc=alsa-devel@alsa-project.org \
    --cc=bgoswami@codeaurora.org \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=lee.jones@linaro.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nagaradh@codeaurora.org \
    --cc=robh@kernel.org \
    --cc=spapothi@codeaurora.org \
    --cc=vinod.koul@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.