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

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

Merge "esoc: mdm-4x: Refactor implementation to separate out PON"

parents 3e06cee7 1e4df586
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4,5 +4,5 @@ ccflags-$(CONFIG_ESOC_DEBUG) := -DDEBUG
obj-$(CONFIG_ESOC)	+= esoc_bus.o
obj-$(CONFIG_ESOC_DEV)	+= esoc_dev.o
obj-$(CONFIG_ESOC_CLIENT)	+= esoc_client.o
obj-$(CONFIG_ESOC_MDM_4x)	+= esoc-mdm-4x.o
obj-$(CONFIG_ESOC_MDM_4x)	+= esoc-mdm-pon.o esoc-mdm-4x.o
obj-$(CONFIG_ESOC_MDM_DRV)	+= esoc-mdm-drv.o
+38 −192
Original line number Diff line number Diff line
@@ -12,58 +12,9 @@

#include <linux/coresight.h>
#include <linux/coresight-cti.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <soc/qcom/sysmon.h>
#include "esoc.h"

#define MDM_PBLRDY_CNT			20
#define INVALID_GPIO			(-1)
#define MDM_GPIO(mdm, i)		(mdm->gpios[i])
#define MDM9x25_LABEL			"MDM9x25"
#define MDM9x25_HSIC			"HSIC"
#define MDM9x35_LABEL			"MDM9x35"
#define MDM9x35_PCIE			"PCIe"
#define MDM9x35_DUAL_LINK		"HSIC+PCIe"
#define MDM9x35_HSIC			"HSIC"
#define MDM2AP_STATUS_TIMEOUT_MS	120000L
#define MDM_MODEM_TIMEOUT		3000
#define DEF_RAMDUMP_TIMEOUT		120000
#define DEF_RAMDUMP_DELAY		2000
#define RD_BUF_SIZE			100
#define SFR_MAX_RETRIES			10
#define SFR_RETRY_INTERVAL		1000
#define MDM_DBG_OFFSET			0x934
#define MDM_DBG_MODE			0x53444247
#define MDM_CTI_NAME			"coresight-cti-rpm-cpu0"
#define MDM_CTI_TRIG			0
#define MDM_CTI_CH			0

enum mdm_gpio {
	AP2MDM_WAKEUP = 0,
	AP2MDM_STATUS,
	AP2MDM_SOFT_RESET,
	AP2MDM_VDD_MIN,
	AP2MDM_CHNLRDY,
	AP2MDM_ERRFATAL,
	AP2MDM_VDDMIN,
	AP2MDM_PMIC_PWR_EN,
	MDM2AP_WAKEUP,
	MDM2AP_ERRFATAL,
	MDM2AP_PBLRDY,
	MDM2AP_STATUS,
	MDM2AP_VDDMIN,
	MDM_LINK_DETECT,
	NUM_GPIOS,
};
#include "esoc-mdm.h"

enum gpio_update_config {
	GPIO_UPDATE_BOOTING_CONFIG = 1,
@@ -76,48 +27,6 @@ enum irq_mask {
	IRQ_PBLRDY = 0x4,
};

struct mdm_ctrl {
	unsigned gpios[NUM_GPIOS];
	spinlock_t status_lock;
	struct workqueue_struct *mdm_queue;
	struct delayed_work mdm2ap_status_check_work;
	struct work_struct mdm_status_work;
	struct work_struct restart_reason_work;
	struct completion debug_done;
	struct device *dev;
	struct pinctrl *pinctrl;
	struct pinctrl_state *gpio_state_booting;
	struct pinctrl_state *gpio_state_running;
	struct pinctrl_state *gpio_state_active;
	struct pinctrl_state *gpio_state_suspend;
	int mdm2ap_status_valid_old_config;
	int soft_reset_inverted;
	int errfatal_irq;
	int status_irq;
	int pblrdy_irq;
	int debug;
	int init;
	bool debug_fail;
	unsigned int dump_timeout_ms;
	unsigned int ramdump_delay_ms;
	struct esoc_clink *esoc;
	bool get_restart_reason;
	unsigned long irq_mask;
	bool ready;
	bool dual_interface;
	u32 status;
	void __iomem *dbg_addr;
	bool dbg_mode;
	struct coresight_cti *cti;
	int trig_cnt;
};

struct mdm_ops {
	struct esoc_clink_ops *clink_ops;
	int (*config_hw)(struct mdm_ctrl *mdm,
				const struct esoc_clink_ops const *ops,
						struct platform_device *pdev);
};

static struct gpio_map {
	const char *name;
@@ -143,7 +52,6 @@ static const int required_gpios[] = {
	AP2MDM_ERRFATAL,
	MDM2AP_STATUS,
	AP2MDM_STATUS,
	AP2MDM_SOFT_RESET
};

static void mdm_debug_gpio_show(struct mdm_ctrl *mdm)
@@ -263,66 +171,6 @@ static void mdm_trigger_dbg(struct mdm_ctrl *mdm)
	}
}

/* This function can be called from atomic context. */
static void mdm_toggle_soft_reset(struct mdm_ctrl *mdm)
{
	int soft_reset_direction_assert = 0,
	    soft_reset_direction_de_assert = 1;

	if (mdm->soft_reset_inverted) {
		soft_reset_direction_assert = 1;
		soft_reset_direction_de_assert = 0;
	}
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
			soft_reset_direction_assert);
	/*
	 * Allow PS hold assert to be detected
	 */
	usleep_range(8000, 9000);
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
			soft_reset_direction_de_assert);
}

static void mdm_do_first_power_on(struct mdm_ctrl *mdm)
{
	int i;
	int pblrdy;
	struct device *dev = mdm->dev;

	dev_dbg(dev, "Powering on modem for the first time\n");
	mdm_toggle_soft_reset(mdm);
	/* Add a delay to allow PON sequence to complete*/
	msleep(50);
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
	for (i = 0; i  < MDM_PBLRDY_CNT; i++) {
		pblrdy = gpio_get_value(MDM_GPIO(mdm, MDM2AP_PBLRDY));
		if (pblrdy)
			break;
		usleep_range(5000, 6000);
	}
	dev_dbg(dev, "pblrdy i:%d\n", i);
	msleep(200);
}

static void mdm_power_down(struct mdm_ctrl *mdm)
{
	struct device *dev = mdm->dev;
	int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
	/* Assert the soft reset line whether mdm2ap_status went low or not */
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
					soft_reset_direction);
	dev_dbg(dev, "Doing a hard reset\n");
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
						soft_reset_direction);
	/*
	* Currently, there is a debounce timer on the charm PMIC. It is
	* necessary to hold the PMIC RESET low for 400ms
	* for the reset to fully take place. Sleep here to ensure the
	* reset has occured before the function exits.
	*/
	msleep(400);
}

static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc)
{
	unsigned long end_time;
@@ -391,7 +239,7 @@ force_poff:
		mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG);
		break;
	case ESOC_RESET:
		mdm_toggle_soft_reset(mdm);
		mdm_toggle_soft_reset(mdm, false);
		break;
	case ESOC_PREPARE_DEBUG:
		/*
@@ -408,7 +256,7 @@ force_poff:
	case ESOC_EXE_DEBUG:
		mdm->debug = 1;
		mdm->trig_cnt = 0;
		mdm_toggle_soft_reset(mdm);
		mdm_toggle_soft_reset(mdm, false);
		/*
		 * wait for ramdumps to be collected
		 * then power down the mdm and switch gpios to booting
@@ -506,7 +354,7 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc)
		break;
	case ESOC_IMG_XFER_RETRY:
		mdm->init = 1;
		mdm_toggle_soft_reset(mdm);
		mdm_toggle_soft_reset(mdm, false);
		break;
	case ESOC_IMG_XFER_FAIL:
		esoc_clink_evt_notify(ESOC_INVALID_STATE, esoc);
@@ -546,25 +394,14 @@ static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc)
		if (!status_down) {
			dev_err(mdm->dev, "%s MDM2AP status did not go low\n",
								__func__);
			gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
					      !!mdm->soft_reset_inverted);
			/*
			 * allow PS hold assert to be detected.
			 * pmic requires 6ms for crash reset case.
			 */
			mdelay(6);
			gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
					      !mdm->soft_reset_inverted);
			mdm_toggle_soft_reset(mdm, true);
		}
		break;
	case ESOC_PRIMARY_REBOOT:
		dev_dbg(mdm->dev, "Triggering mdm cold reset");
		mdm->ready = 0;
		gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
				!!mdm->soft_reset_inverted);
		mdelay(300);
		gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
				!mdm->soft_reset_inverted);
		mdm_disable_irqs(mdm);
		mdm->debug = 0;
		mdm->ready = false;
		mdm_cold_reset(mdm);
		break;
	};
	return;
@@ -699,7 +536,6 @@ static int mdm_dt_parse_gpios(struct mdm_ctrl *mdm)
{
	int i, val, rc = 0;
	struct device_node *node = mdm->dev->of_node;
	enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;

	for (i = 0; i < NUM_GPIOS; i++)
		mdm->gpios[i] = INVALID_GPIO;
@@ -710,13 +546,6 @@ static int mdm_dt_parse_gpios(struct mdm_ctrl *mdm)
			MDM_GPIO(mdm, gpio_map[i].index) = val;
	}
	/* These two are special because they can be inverted. */
	val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio",
						0, &flags);
	if (val >= 0) {
		MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val;
		if (flags & OF_GPIO_ACTIVE_LOW)
			mdm->soft_reset_inverted = 1;
	}
	/* Verify that the required gpios have valid values */
	for (i = 0; i < ARRAY_SIZE(required_gpios); i++) {
		if (MDM_GPIO(mdm, required_gpios[i]) == INVALID_GPIO) {
@@ -767,13 +596,6 @@ static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev)
			goto fatal_err;
		}
	}
	if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET))) {
		if (gpio_request(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
					 "AP2MDM_SOFT_RESET")) {
			dev_err(dev, "Cannot config AP2MDM_SOFT_RESET gpio\n");
			goto fatal_err;
		}
	}
	if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_WAKEUP))) {
		if (gpio_request(MDM_GPIO(mdm, AP2MDM_WAKEUP),
					"AP2MDM_WAKEUP")) {
@@ -909,13 +731,16 @@ err_state_active:
	return retval;
}
static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
					struct esoc_clink_ops const *ops,
					const struct mdm_ops *ops,
					struct platform_device *pdev)
{
	int ret;
	struct esoc_clink *esoc;
	const struct esoc_clink_ops *const clink_ops = ops->clink_ops;
	const struct mdm_pon_ops *pon_ops = ops->pon_ops;

	mdm->dev = &pdev->dev;
	mdm->pon_ops = pon_ops;
	esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
	if (IS_ERR(esoc)) {
		dev_err(mdm->dev, "cannot allocate esoc device\n");
@@ -932,10 +757,18 @@ static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
	if (ret)
		return ret;
	dev_err(mdm->dev, "parsing gpio done\n");
	ret = mdm_pon_dt_init(mdm);
	if (ret)
		return ret;
	dev_dbg(mdm->dev, "pon dt init done\n");
	ret = mdm_pinctrl_init(mdm);
	if (ret)
		return ret;
	dev_err(mdm->dev, "pinctrl init done\n");
	ret = mdm_pon_setup(mdm);
	if (ret)
		return ret;
	dev_dbg(mdm->dev, "pon setup done\n");
	ret = mdm_configure_ipc(mdm, pdev);
	if (ret)
		return ret;
@@ -943,7 +776,7 @@ static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
	dev_err(mdm->dev, "ipc configure done\n");
	esoc->name = MDM9x25_LABEL;
	esoc->link_name = MDM9x25_HSIC;
	esoc->clink_ops = ops;
	esoc->clink_ops = clink_ops;
	esoc->parent = mdm->dev;
	esoc->owner = THIS_MODULE;
	esoc->np = pdev->dev.of_node;
@@ -966,14 +799,17 @@ static int mdm9x25_setup_hw(struct mdm_ctrl *mdm,
}

static int mdm9x35_setup_hw(struct mdm_ctrl *mdm,
					struct esoc_clink_ops const *ops,
					const struct mdm_ops *ops,
					struct platform_device *pdev)
{
	int ret;
	struct device_node *node;
	struct esoc_clink *esoc;
	const struct esoc_clink_ops *const clink_ops = ops->clink_ops;
	const struct mdm_pon_ops *pon_ops = ops->pon_ops;

	mdm->dev = &pdev->dev;
	mdm->pon_ops = pon_ops;
	node = pdev->dev.of_node;
	esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL);
	if (IS_ERR(esoc)) {
@@ -991,10 +827,18 @@ static int mdm9x35_setup_hw(struct mdm_ctrl *mdm,
	if (ret)
		return ret;
	dev_dbg(mdm->dev, "parsing gpio done\n");
	ret = mdm_pon_dt_init(mdm);
	if (ret)
		return ret;
	dev_dbg(mdm->dev, "pon dt init done\n");
	ret = mdm_pinctrl_init(mdm);
	if (ret)
		return ret;
	dev_dbg(mdm->dev, "pinctrl init done\n");
	ret = mdm_pon_setup(mdm);
	if (ret)
		return ret;
	dev_dbg(mdm->dev, "pon setup done\n");
	ret = mdm_configure_ipc(mdm, pdev);
	if (ret)
		return ret;
@@ -1020,7 +864,7 @@ static int mdm9x35_setup_hw(struct mdm_ctrl *mdm,
		esoc->link_name = MDM9x35_DUAL_LINK;
	else
		esoc->link_name = MDM9x35_HSIC;
	esoc->clink_ops = ops;
	esoc->clink_ops = clink_ops;
	esoc->parent = mdm->dev;
	esoc->owner = THIS_MODULE;
	esoc->np = pdev->dev.of_node;
@@ -1051,11 +895,13 @@ static struct esoc_clink_ops mdm_cops = {
static struct mdm_ops mdm9x25_ops = {
	.clink_ops = &mdm_cops,
	.config_hw = mdm9x25_setup_hw,
	.pon_ops = &mdm9x25_pon_ops,
};

static struct mdm_ops mdm9x35_ops = {
	.clink_ops = &mdm_cops,
	.config_hw = mdm9x35_setup_hw,
	.pon_ops = &mdm9x35_pon_ops,
};

static const struct of_device_id mdm_dt_match[] = {
@@ -1081,7 +927,7 @@ static int mdm_probe(struct platform_device *pdev)
	mdm = devm_kzalloc(&pdev->dev, sizeof(*mdm), GFP_KERNEL);
	if (IS_ERR(mdm))
		return PTR_ERR(mdm);
	return mdm_ops->config_hw(mdm, mdm_ops->clink_ops, pdev);
	return mdm_ops->config_hw(mdm, mdm_ops, pdev);
}

static struct platform_driver mdm_driver = {
+156 −0
Original line number Diff line number Diff line
/* Copyright (c) 2014-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 "esoc-mdm.h"

/* This function can be called from atomic context. */
static int mdm4x_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
{
	int soft_reset_direction_assert = 0,
	    soft_reset_direction_de_assert = 1;

	if (mdm->soft_reset_inverted) {
		soft_reset_direction_assert = 1;
		soft_reset_direction_de_assert = 0;
	}
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
			soft_reset_direction_assert);
	/*
	 * Allow PS hold assert to be detected
	 */
	if (!atomic)
		usleep_range(8000, 9000);
	else
		mdelay(6);
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
			soft_reset_direction_de_assert);
	return 0;
}

static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
{
	int i;
	int pblrdy;
	struct device *dev = mdm->dev;

	dev_dbg(dev, "Powering on modem for the first time\n");
	mdm4x_toggle_soft_reset(mdm, false);
	/* Add a delay to allow PON sequence to complete*/
	msleep(50);
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
	if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) {
		for (i = 0; i  < MDM_PBLRDY_CNT; i++) {
			pblrdy = gpio_get_value(MDM_GPIO(mdm, MDM2AP_PBLRDY));
			if (pblrdy)
				break;
			usleep_range(5000, 6000);
		}
		dev_dbg(dev, "pblrdy i:%d\n", i);
		msleep(200);
	}
	/*
	 * No PBLRDY gpio associated with this modem
	 * Send request for image. Let userspace confirm establishment of
	 * link to external modem.
	 */
	else
		esoc_clink_queue_request(ESOC_REQ_IMG, mdm->esoc);
	return 0;
}

static int mdm4x_power_down(struct mdm_ctrl *mdm)
{
	struct device *dev = mdm->dev;
	int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
	/* Assert the soft reset line whether mdm2ap_status went low or not */
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
					soft_reset_direction);
	dev_dbg(dev, "Doing a hard reset\n");
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
						soft_reset_direction);
	/*
	* Currently, there is a debounce timer on the charm PMIC. It is
	* necessary to hold the PMIC RESET low for 400ms
	* for the reset to fully take place. Sleep here to ensure the
	* reset has occurred before the function exits.
	*/
	msleep(400);
	return 0;
}

static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
{
	dev_dbg(mdm->dev, "Triggering mdm cold reset");
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
			!!mdm->soft_reset_inverted);
	msleep(300);
	gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
			!mdm->soft_reset_inverted);
}

static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
{
	int val;
	struct device_node *node = mdm->dev->of_node;
	enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;

	val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio",
						0, &flags);
	if (val >= 0) {
		MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val;
		if (flags & OF_GPIO_ACTIVE_LOW)
			mdm->soft_reset_inverted = 1;
		return 0;
	} else
		return -EIO;
}

static int mdm4x_pon_setup(struct mdm_ctrl *mdm)
{
	struct device *dev = mdm->dev;

	if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET))) {
		if (gpio_request(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
					 "AP2MDM_SOFT_RESET")) {
			dev_err(dev, "Cannot config AP2MDM_SOFT_RESET gpio\n");
			return -EIO;
		}
	}
	return 0;
}

struct mdm_pon_ops mdm9x25_pon_ops = {
	.pon = mdm4x_do_first_power_on,
	.soft_reset = mdm4x_toggle_soft_reset,
	.poff_force = mdm4x_power_down,
	.cold_reset = mdm4x_cold_reset,
	.dt_init = mdm4x_pon_dt_init,
	.setup = mdm4x_pon_setup,
};

struct mdm_pon_ops mdm9x35_pon_ops = {
	.pon = mdm4x_do_first_power_on,
	.soft_reset = mdm4x_toggle_soft_reset,
	.poff_force = mdm4x_power_down,
	.cold_reset = mdm4x_cold_reset,
	.dt_init = mdm4x_pon_dt_init,
	.setup = mdm4x_pon_setup,
};

struct mdm_pon_ops mdm9x45_pon_ops = {
	.pon = mdm4x_do_first_power_on,
	.soft_reset = mdm4x_toggle_soft_reset,
	.poff_force = mdm4x_power_down,
	.cold_reset = mdm4x_cold_reset,
	.dt_init = mdm4x_pon_dt_init,
	.setup = mdm4x_pon_setup,
};
+153 −0
Original line number Diff line number Diff line
/* Copyright (c) 2014-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 __ESOC_MDM_H__
#define __ESOC_MDM_H__

#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include "esoc.h"

#define MDM_PBLRDY_CNT			20
#define INVALID_GPIO			(-1)
#define MDM_GPIO(mdm, i)		(mdm->gpios[i])
#define MDM9x25_LABEL			"MDM9x25"
#define MDM9x25_HSIC			"HSIC"
#define MDM9x35_LABEL			"MDM9x35"
#define MDM9x35_PCIE			"PCIe"
#define MDM9x35_DUAL_LINK		"HSIC+PCIe"
#define MDM9x35_HSIC			"HSIC"
#define MDM9x45_LABEL			"MDM9x45"
#define MDM9x45_PCIE			"PCIe"
#define MDM2AP_STATUS_TIMEOUT_MS	120000L
#define MDM_MODEM_TIMEOUT		3000
#define DEF_RAMDUMP_TIMEOUT		120000
#define DEF_RAMDUMP_DELAY		2000
#define RD_BUF_SIZE			100
#define SFR_MAX_RETRIES			10
#define SFR_RETRY_INTERVAL		1000
#define MDM_DBG_OFFSET			0x934
#define MDM_DBG_MODE			0x53444247
#define MDM_CTI_NAME			"coresight-cti-rpm-cpu0"
#define MDM_CTI_TRIG			0
#define MDM_CTI_CH			0

enum mdm_gpio {
	AP2MDM_WAKEUP = 0,
	AP2MDM_STATUS,
	AP2MDM_SOFT_RESET,
	AP2MDM_VDD_MIN,
	AP2MDM_CHNLRDY,
	AP2MDM_ERRFATAL,
	AP2MDM_VDDMIN,
	AP2MDM_PMIC_PWR_EN,
	MDM2AP_WAKEUP,
	MDM2AP_ERRFATAL,
	MDM2AP_PBLRDY,
	MDM2AP_STATUS,
	MDM2AP_VDDMIN,
	MDM_LINK_DETECT,
	NUM_GPIOS,
};

struct mdm_pon_ops;

struct mdm_ctrl {
	unsigned gpios[NUM_GPIOS];
	spinlock_t status_lock;
	struct workqueue_struct *mdm_queue;
	struct delayed_work mdm2ap_status_check_work;
	struct work_struct mdm_status_work;
	struct work_struct restart_reason_work;
	struct completion debug_done;
	struct device *dev;
	struct pinctrl *pinctrl;
	struct pinctrl_state *gpio_state_booting;
	struct pinctrl_state *gpio_state_running;
	struct pinctrl_state *gpio_state_active;
	struct pinctrl_state *gpio_state_suspend;
	int mdm2ap_status_valid_old_config;
	int soft_reset_inverted;
	int errfatal_irq;
	int status_irq;
	int pblrdy_irq;
	int debug;
	int init;
	bool debug_fail;
	unsigned int dump_timeout_ms;
	unsigned int ramdump_delay_ms;
	struct esoc_clink *esoc;
	bool get_restart_reason;
	unsigned long irq_mask;
	bool ready;
	bool dual_interface;
	u32 status;
	void __iomem *dbg_addr;
	bool dbg_mode;
	struct coresight_cti *cti;
	int trig_cnt;
	const struct mdm_pon_ops *pon_ops;
};

struct mdm_pon_ops {
	int (*pon)(struct mdm_ctrl *mdm);
	int (*soft_reset)(struct mdm_ctrl *mdm, bool atomic);
	int (*poff_force)(struct mdm_ctrl *mdm);
	int (*poff_cleanup)(struct mdm_ctrl *mdm);
	void (*cold_reset)(struct mdm_ctrl *mdm);
	int (*dt_init)(struct mdm_ctrl *mdm);
	int (*setup)(struct mdm_ctrl *mdm);
};

struct mdm_ops {
	struct esoc_clink_ops *clink_ops;
	struct mdm_pon_ops *pon_ops;
	int (*config_hw)(struct mdm_ctrl *mdm, const struct mdm_ops *ops,
					struct platform_device *pdev);
};

static inline int mdm_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
{
	return mdm->pon_ops->soft_reset(mdm, atomic);
}
static inline int mdm_do_first_power_on(struct mdm_ctrl *mdm)
{
	return mdm->pon_ops->pon(mdm);
}
static inline int mdm_power_down(struct mdm_ctrl *mdm)
{
	return mdm->pon_ops->poff_force(mdm);
}
static inline void mdm_cold_reset(struct mdm_ctrl *mdm)
{
	mdm->pon_ops->cold_reset(mdm);
}
static inline int mdm_pon_dt_init(struct mdm_ctrl *mdm)
{
	return mdm->pon_ops->dt_init(mdm);
}
static inline int mdm_pon_setup(struct mdm_ctrl *mdm)
{
	return mdm->pon_ops->setup(mdm);
}

extern struct mdm_pon_ops mdm9x25_pon_ops;
extern struct mdm_pon_ops mdm9x35_pon_ops;
extern struct mdm_pon_ops mdm9x45_pon_ops;
#endif