Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5020673 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: mfd: Move codec reset gpio config to early boot"

parents 03e8fc55 569ee66d
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -355,6 +355,18 @@ Required properties:

 - elemental-addr:                         slimbus slave enumeration address.

* wcd_gpio_ctrl

Required properties:

 - compatible :                            "qcom,wcd-gpio-ctrl"

 - qcom,cdc-rst-n-gpio :                   TLMM GPIO number

 - pinctrl-names:                          Pinctrl state names for each pin
                                           group configuration.
 - pinctrl-x:                              Defines pinctrl state for each pin
                                           group.
Example:

	qcom,msm-pcm {
@@ -611,6 +623,15 @@ Example:
		compatible = "qcom,msm_dai_slim";
		elemental-addr = [ff ff ff fe 17 02];
	};

	wcd_gpio_ctrl {
		compatible = "qcom,wcd-gpio-ctrl";
		qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
		pinctrl-names = "aud_active", "aud_sleep";
		pinctrl-0 = <&cdc_reset_active>;
		pinctrl-1 = <&cdc_reset_sleep>;
	};

* MSM8916 ASoC Machine driver

Required properties:
+5 −0
Original line number Diff line number Diff line
@@ -8,6 +8,11 @@ Required properties:
 - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits)

 - qcom,cdc-reset-gpio: gpio used for codec SOC reset.
                        If this property is not defined, it is expected
                        to atleast have "qcom,wcd-rst-n-gpio" to be defined.
 - qcom,wcd-rst-gpio-node: Phandle reference to the DT node having codec reset gpio
                        configuration. If this property is not defined, it is
                        expected to atleast define "qcom,cdc-reset-gpio" property.

 - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node.
 - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV.
+1 −1
Original line number Diff line number Diff line
@@ -183,4 +183,4 @@ obj-$(CONFIG_WCD9330_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
						wcd9xxx-core-resource.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
					wcd9335-tables.o wcd-gpio-ctrl.o
+188 −0
Original line number Diff line number Diff line
/* 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");
+69 −16
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/mfd/wcd9xxx/core-resource.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/delay.h>
@@ -1173,6 +1174,28 @@ 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");
@@ -1215,6 +1238,12 @@ static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
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);
@@ -1743,6 +1772,15 @@ 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);
		else
			wcd_gpio_ctrl_select_sleep_state(wcd9xxx->wcd_rst_np);

		return;
	}

	if (pdata->use_pinctrl) {
		if (active == true)
			pinctrl_select_state(pinctrl_info.pinctrl,
@@ -2219,11 +2257,18 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
				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;
		}

		if (i2c_check_functionality(client->adapter,
					    I2C_FUNC_I2C) == 0) {
@@ -2233,7 +2278,6 @@ static int wcd9xxx_i2c_probe(struct i2c_client *client,
		}
		dev_set_drvdata(&client->dev, wcd9xxx);
		wcd9xxx->dev = &client->dev;
		wcd9xxx->reset_gpio = pdata->reset_gpio;
		wcd9xxx->dev_up = true;
		if (client->dev.of_node)
			wcd9xxx->mclk_rate = pdata->mclk_rate;
@@ -2672,15 +2716,19 @@ static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
	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);
				"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);
@@ -2924,12 +2972,17 @@ static int wcd9xxx_slim_probe(struct slim_device *slim)
	wcd9xxx->dev = &slim->dev;
	wcd9xxx->mclk_rate = pdata->mclk_rate;
	wcd9xxx->dev_up = true;
	wcd9xxx->wcd_rst_np = pdata->wcd_rst_np;

	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;
	}

	ret = wcd9xxx_init_supplies(wcd9xxx, pdata);
	if (ret) {
Loading