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

Commit 47004e09 authored by Ashish Kori's avatar Ashish Kori
Browse files

spi: qcom-geni-se: Add SSR support for SSC QUPs



This change is related to SSC Qup SSR and it's handling. Common driver
registers for PIL notification and handles SSR shutdown/restart callbacks
which in turn calls respective bus driver. Subsystem notification is DTSI
based entry.

On some platforms SSC QUPs, present on different subsystem
(e.g. sensor/adsp/slpi), are used by Apps processor. When these
subsystems go through SSR, apps driver must release the resources
- clocks, gpios, bus-votes etc and not attempt to access hardware
registers as well until SSR is finished. This is now handled by QUP
common driver by registering for SSR callbacks. On SSR down it notifies
all SE bus drivers to release the resource and force_suspend device. And
on SSR up notification common driver requests for firmware loading and
lets SE drivers start using the QUP again. In addition to this, client
drivers are also expected to handle data transfer errors on SSR and
initiate next data transfer only after SSR is complete by checking for
following sysfs node exposed by common driver - 'ssc_qup_state'.

Change-Id: I5f9fc36e6588299ee9d7d1b59ac5b9ee57ccf5ad
Signed-off-by: default avatarAshish Kori <akori@codeaurora.org>
parent 73ad9c51
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ Optional properties:
				and Corex/2x paths.
- qcom,vote-for-bw: Boolean flag to check if ab/ib vote should be given
		    as bandwidth or BCM threashold.
- qcom,subsys-name: SSC QUPv3 subsystem name for SSR notification registration.

Optional subnodes:
qcom,iommu_qupv3_geni_se_cb:	Child node representing the QUPV3 context
@@ -31,6 +32,7 @@ Subnode Required properties:
Example:
	qupv3_0: qcom,qupv3_0_geni_se@8c0000 {
		compatible = "qcom,qupv3-geni-se";
		qcom,subsys-name = "adsp";
		reg = <0x8c0000 0x6000>;
		qcom,bus-mas-id = <100>;
		qcom,bus-slv-id = <300>;
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ Optional properties:
- qcom,rt:	Specifies if the framework worker thread for this
		controller device should have "real-time" priority.
- qcom,disable-autosuspend: Specifies to disable runtime PM auto suspend.
- ssr-enable:	Required only for SSC QupV3 client for SSR notification.

SPI slave nodes must be children of the SPI master node and can contain
the following properties.
+129 −3
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@
#define MAX_CLK_PERF_LEVEL 32
static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000,
				100000000, 150000000, 200000000, 236000000};
/* SCM Call Id */
#define SSR_SCM_CMD	0x1

struct bus_vectors {
	int src;
@@ -89,6 +91,7 @@ struct bus_vectors {
 * @update:		Usecase index for icb voting.
 * @vote_for_bw:	To check if we have to vote for BW or BCM threashold
			in ab/ib ICB voting.
 * @struct ssc_qup_ssr: Structure to represent SSC Qupv3 SSR Structure.
 */
struct geni_se_device {
	struct device *dev;
@@ -125,6 +128,7 @@ struct geni_se_device {
	struct msm_bus_scale_pdata *pdata;
	int update;
	bool vote_for_bw;
	struct ssc_qup_ssr ssr;
};

#define HW_VER_MAJOR_MASK GENMASK(31, 28)
@@ -351,6 +355,101 @@ static int geni_se_select_fifo_mode(void __iomem *base)
	return 0;
}

static ssize_t ssc_qup_state_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	struct geni_se_device *geni_se_dev = dev_get_drvdata(dev);

	return snprintf(buf, sizeof(int), "%d\n",
				!geni_se_dev->ssr.is_ssr_down);
}

static DEVICE_ATTR_RO(ssc_qup_state);

static void geni_se_ssc_qup_down(struct geni_se_device *dev)
{
	struct se_geni_rsc *rsc = NULL;

	dev->ssr.is_ssr_down = true;
	list_for_each_entry(rsc, &dev->ssr.active_list_head,
					rsc_ssr.active_list) {
		rsc->rsc_ssr.force_suspend(rsc->ctrl_dev);
	}
}

static void geni_se_ssc_qup_up(struct geni_se_device *dev)
{
	int ret = 0;
	struct scm_desc desc;
	struct se_geni_rsc *rsc = NULL;

	/* Passing dummy argument as it is scm call requirement */
	desc.args[0] = 0x0;
	desc.arginfo = SCM_ARGS(1, SCM_VAL);

	ret = scm_call2(SCM_SIP_FNID(TZ_SVC_QUP_FW_LOAD, SSR_SCM_CMD), &desc);
	if (ret) {
		dev_err(dev->dev, "Unable to load firmware after SSR\n");
		return;
	}

	list_for_each_entry(rsc, &dev->ssr.active_list_head,
					rsc_ssr.active_list) {
		rsc->rsc_ssr.force_resume(rsc->ctrl_dev);
	}

	dev->ssr.is_ssr_down = false;
}

static int geni_se_ssr_notify_block(struct notifier_block *n,
						unsigned long code, void *_cmd)
{
	struct ssc_qup_nb *ssc_qup_nb = container_of(n, struct ssc_qup_nb, nb);
	struct ssc_qup_ssr *ssr = container_of(ssc_qup_nb, struct ssc_qup_ssr,
					ssc_qup_nb);
	struct geni_se_device *dev = container_of(ssr, struct geni_se_device,
						ssr);

	switch (code) {
	case SUBSYS_BEFORE_SHUTDOWN:
		geni_se_ssc_qup_down(dev);
		GENI_SE_DBG(dev->log_ctx, false, NULL,
				"SSR notification before power down\n");
		break;
	case SUBSYS_AFTER_POWERUP:
		if (dev->ssr.probe_completed)
			geni_se_ssc_qup_up(dev);
		else
			dev->ssr.probe_completed = true;

		GENI_SE_DBG(dev->log_ctx, false, NULL,
				"SSR notification after power up\n");
		break;
	default:
		break;
	}

	return 0;
}

static int geni_se_ssc_qup_ssr_reg(struct geni_se_device *dev)
{
	dev->ssr.ssc_qup_nb.nb.notifier_call = geni_se_ssr_notify_block;
	dev->ssr.ssc_qup_nb.next = subsys_notif_register_notifier(
				dev->ssr.subsys_name, &dev->ssr.ssc_qup_nb.nb);

	if (IS_ERR_OR_NULL(dev->ssr.ssc_qup_nb.next)) {
		dev_err(dev->dev,
			"subsys_notif_register_notifier failed %ld\n",
			PTR_ERR(dev->ssr.ssc_qup_nb.next));
		return PTR_ERR(dev->ssr.ssc_qup_nb.next);
	}

	GENI_SE_DBG(dev->log_ctx, false, NULL, "SSR registration done\n");

	return 0;
}

static int geni_se_select_dma_mode(void __iomem *base)
{
	int proto = get_se_proto(base);
@@ -1096,6 +1195,12 @@ int geni_se_resources_init(struct se_geni_rsc *rsc,

	INIT_LIST_HEAD(&rsc->ab_list);
	INIT_LIST_HEAD(&rsc->ib_list);
	if (geni_se_dev->ssr.subsys_name && rsc->rsc_ssr.ssr_enable) {
		INIT_LIST_HEAD(&rsc->rsc_ssr.active_list);
		list_add(&rsc->rsc_ssr.active_list,
				&geni_se_dev->ssr.active_list_head);
	}

	ret = geni_se_iommu_map_and_attach(geni_se_dev);
	if (ret)
		GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
@@ -1836,13 +1941,27 @@ static int geni_se_probe(struct platform_device *pdev)
	ret = of_platform_populate(dev->of_node, geni_se_dt_match, NULL, dev);
	if (ret) {
		dev_err(dev, "%s: Error populating children\n", __func__);
		devm_iounmap(dev, geni_se_dev->base);
		devm_kfree(dev, geni_se_dev);
		return ret;
	}

	ret = of_property_read_string(geni_se_dev->dev->of_node,
			"qcom,subsys-name", &geni_se_dev->ssr.subsys_name);
	if (!ret) {
		INIT_LIST_HEAD(&geni_se_dev->ssr.active_list_head);
		geni_se_dev->ssr.probe_completed = false;
		ret = geni_se_ssc_qup_ssr_reg(geni_se_dev);
		if (ret) {
			dev_err(dev, "Unable to register SSR notification\n");
			return ret;
		}

		sysfs_create_file(&geni_se_dev->dev->kobj,
			 &dev_attr_ssc_qup_state.attr);
	}

	GENI_SE_DBG(geni_se_dev->log_ctx, false, NULL,
		    "%s: Probe successful\n", __func__);
	return ret;
	return 0;
}

static int geni_se_remove(struct platform_device *pdev)
@@ -1854,6 +1973,13 @@ static int geni_se_remove(struct platform_device *pdev)
		arm_iommu_detach_device(geni_se_dev->cb_dev);
		arm_iommu_release_mapping(geni_se_dev->iommu_map);
	}
	if (geni_se_dev->ssr.subsys_name) {
		subsys_notif_unregister_notifier(
				geni_se_dev->ssr.ssc_qup_nb.next,
				&geni_se_dev->ssr.ssc_qup_nb.nb);
		sysfs_remove_file(&geni_se_dev->dev->kobj,
				&dev_attr_ssc_qup_state.attr);
	}
	ipc_log_context_destroy(geni_se_dev->log_ctx);
	devm_iounmap(dev, geni_se_dev->base);
	devm_kfree(dev, geni_se_dev);
+133 −4
Original line number Diff line number Diff line
@@ -124,6 +124,12 @@ struct spi_geni_gsi {
	struct gsi_desc_cb desc_cb;
};

struct spi_geni_ssr {
	struct mutex ssr_lock;
	bool is_ssr_down;
	bool xfer_prepared;
};

struct spi_geni_master {
	struct se_geni_rsc spi_rsc;
	resource_size_t phys_addr;
@@ -163,9 +169,12 @@ struct spi_geni_master {
	bool shared_se;
	bool dis_autosuspend;
	bool cmd_done;
	struct spi_geni_ssr spi_ssr;
};

static void spi_slv_setup(struct spi_geni_master *mas);
static int ssr_spi_force_suspend(struct device *dev);
static int ssr_spi_force_resume(struct device *dev);

static ssize_t show_slave_state(struct device *dev,
		struct device_attribute *attr, char *buf)
@@ -788,6 +797,13 @@ static int spi_geni_prepare_message(struct spi_master *spi,
	int ret = 0;
	struct spi_geni_master *mas = spi_master_get_devdata(spi);

	mutex_lock(&mas->spi_ssr.ssr_lock);
	/* Bail out if prepare_transfer didn't happen due to SSR */
	if (mas->spi_ssr.is_ssr_down || !mas->spi_ssr.xfer_prepared) {
		mutex_unlock(&mas->spi_ssr.ssr_lock);
		return -EINVAL;
	}

	mas->cur_xfer_mode = select_xfer_mode(spi, spi_msg);

	if (mas->cur_xfer_mode < 0) {
@@ -803,6 +819,7 @@ static int spi_geni_prepare_message(struct spi_master *spi,
		geni_se_select_mode(mas->base, mas->cur_xfer_mode);
		ret = setup_fifo_params(spi_msg->spi, spi);
	}
	mutex_unlock(&mas->spi_ssr.ssr_lock);

	return ret;
}
@@ -826,6 +843,19 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
	u32 max_speed = spi->cur_msg->spi->max_speed_hz;
	struct se_geni_rsc *rsc = &mas->spi_rsc;

	mutex_lock(&mas->spi_ssr.ssr_lock);
	if (mas->spi_ssr.is_ssr_down) {
		/*
		 * xfer_prepared will be set to true once prepare_transfer
		 * hardware is complete.
		 * It used in prepare_message and transfer_one to bail out
		 * during SSR.
		 */
		mas->spi_ssr.xfer_prepared = false;
		mutex_unlock(&mas->spi_ssr.ssr_lock);
		return 0;
	}

	/* Adjust the IB based on the max speed of the slave.*/
	rsc->ib = max_speed * DEFAULT_BUS_WIDTH;
	if (mas->shared_se) {
@@ -864,6 +894,7 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)

		if (unlikely(proto != SPI_SLAVE)) {
			dev_err(mas->dev, "Invalid proto %d\n", proto);
			mutex_unlock(&mas->spi_ssr.ssr_lock);
			return -ENXIO;
		}
	}
@@ -877,6 +908,7 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
		proto = get_se_proto(mas->base);
		if ((unlikely(proto != SPI)) && (!spi->slave)) {
			dev_err(mas->dev, "Invalid proto %d\n", proto);
			mutex_unlock(&mas->spi_ssr.ssr_lock);
			return -ENXIO;
		}

@@ -968,6 +1000,8 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
					"Auto Suspend is disabled\n");
	}
exit_prepare_transfer_hardware:
	mas->spi_ssr.xfer_prepared = true;
	mutex_unlock(&mas->spi_ssr.ssr_lock);
	return ret;
}

@@ -975,6 +1009,16 @@ static int spi_geni_unprepare_transfer_hardware(struct spi_master *spi)
{
	struct spi_geni_master *mas = spi_master_get_devdata(spi);
	int count = 0;

	mutex_lock(&mas->spi_ssr.ssr_lock);
	if (mas->spi_ssr.is_ssr_down || !mas->spi_ssr.xfer_prepared) {
		/* Call runtime_put to match get in prepare_transfer */
		pm_runtime_put_noidle(mas->dev);
		mutex_unlock(&mas->spi_ssr.ssr_lock);
		return -EINVAL;
	}
	mutex_unlock(&mas->spi_ssr.ssr_lock);

	if (mas->shared_se) {
		struct se_geni_rsc *rsc;
		int ret = 0;
@@ -1183,13 +1227,24 @@ static int spi_geni_transfer_one(struct spi_master *spi,
		return -EINVAL;
	}

	mutex_lock(&mas->spi_ssr.ssr_lock);
	if (mas->spi_ssr.is_ssr_down || !mas->spi_ssr.xfer_prepared) {
		mutex_unlock(&mas->spi_ssr.ssr_lock);
		return -EINVAL;
	}

	if (mas->cur_xfer_mode != GSI_DMA) {
		reinit_completion(&mas->xfer_done);
		setup_fifo_xfer(xfer, mas, slv->mode, spi);
		if (spi->slave)
			spi->slave_state = true;
		mutex_unlock(&mas->spi_ssr.ssr_lock);
		timeout = wait_for_completion_timeout(&mas->xfer_done,
					msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
		mutex_lock(&mas->spi_ssr.ssr_lock);
		if (mas->spi_ssr.is_ssr_down)
			goto err_ssr_transfer_one;

		if (spi->slave)
			spi->slave_state = false;

@@ -1256,16 +1311,20 @@ static int spi_geni_transfer_one(struct spi_master *spi,
			}
		}
	}
	mutex_unlock(&mas->spi_ssr.ssr_lock);
	return ret;
err_gsi_geni_transfer_one:
	geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc);
	dmaengine_terminate_all(mas->tx);
	mutex_unlock(&mas->spi_ssr.ssr_lock);
	return ret;
err_fifo_geni_transfer_one:
	if (!spi->slave)
		handle_fifo_timeout(mas, xfer);
	if (spi->slave)
		geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc);
err_ssr_transfer_one:
	mutex_unlock(&mas->spi_ssr.ssr_lock);
	return ret;
}

@@ -1302,6 +1361,8 @@ static void geni_spi_handle_tx(struct spi_geni_master *mas)
		int bytes_per_fifo = tx_fifo_width;
		int bytes_to_write = 0;

		if (mas->spi_ssr.is_ssr_down)
			break;
		if ((mas->tx_fifo_width % mas->cur_word_len))
			bytes_per_fifo =
				(mas->cur_word_len / BITS_PER_BYTE) + 1;
@@ -1314,7 +1375,7 @@ static void geni_spi_handle_tx(struct spi_geni_master *mas)
		mb();
	}
	mas->tx_rem_bytes -= max_bytes;
	if (!mas->tx_rem_bytes) {
	if (!mas->tx_rem_bytes && !mas->spi_ssr.is_ssr_down) {
		geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
		/* Barrier here before return to prevent further ISRs */
		mb();
@@ -1325,14 +1386,18 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
{
	int i = 0;
	int fifo_width = (mas->tx_fifo_width >> 3);
	u32 rx_fifo_status = geni_read_reg(mas->base, SE_GENI_RX_FIFO_STATUS);
	u32 rx_fifo_status;
	int rx_bytes = 0;
	int rx_wc = 0;
	u8 *rx_buf = NULL;

	if (mas->spi_ssr.is_ssr_down)
		return;

	if (!mas->cur_xfer)
		return;

	rx_fifo_status = geni_read_reg(mas->base, SE_GENI_RX_FIFO_STATUS);
	rx_buf = mas->cur_xfer->rx_buf;
	rx_wc = (rx_fifo_status & RX_FIFO_WC_MSK);
	if (rx_fifo_status & RX_LAST) {
@@ -1358,6 +1423,8 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
		int read_bytes = 0;
		int j;

		if (mas->spi_ssr.is_ssr_down)
			break;
		if ((mas->tx_fifo_width % mas->cur_word_len))
			bytes_per_fifo =
				(mas->cur_word_len / BITS_PER_BYTE) + 1;
@@ -1380,7 +1447,15 @@ static irqreturn_t geni_spi_irq(int irq, void *data)
				"%s: device is suspended\n", __func__);
		goto exit_geni_spi_irq;
	}

	if (mas->spi_ssr.is_ssr_down) {
		mas->cmd_done = false;
		complete(&mas->xfer_done);
		dev_err(mas->dev, "IRQ at SSR down\n");
		return IRQ_HANDLED;
	}
	m_irq = geni_read_reg(mas->base, SE_GENI_M_IRQ_STATUS);

	if (mas->cur_xfer_mode == FIFO_MODE) {
		if ((m_irq & M_RX_FIFO_WATERMARK_EN) ||
						(m_irq & M_RX_FIFO_LAST_EN))
@@ -1436,6 +1511,7 @@ static irqreturn_t geni_spi_irq(int irq, void *data)
			mas->cmd_done = true;
	}
exit_geni_spi_irq:
	if (!mas->spi_ssr.is_ssr_down)
		geni_write_reg(m_irq, mas->base, SE_GENI_M_IRQ_CLEAR);
	if (mas->cmd_done) {
		mas->cmd_done = false;
@@ -1488,6 +1564,8 @@ static int spi_geni_probe(struct platform_device *pdev)
	}
	geni_mas->wrapper_dev = &wrapper_pdev->dev;
	geni_mas->spi_rsc.wrapper_dev = &wrapper_pdev->dev;
	rsc->rsc_ssr.ssr_enable = of_property_read_bool(pdev->dev.of_node,
			"ssr-enable");
	ret = geni_se_resources_init(rsc, SPI_CORE2X_VOTE,
				     (DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));
	if (ret) {
@@ -1624,10 +1702,12 @@ static int spi_geni_probe(struct platform_device *pdev)
	spi->unprepare_transfer_hardware
			= spi_geni_unprepare_transfer_hardware;
	spi->auto_runtime_pm = false;

	rsc->rsc_ssr.force_suspend = ssr_spi_force_suspend;
	rsc->rsc_ssr.force_resume = ssr_spi_force_resume;
	init_completion(&geni_mas->xfer_done);
	init_completion(&geni_mas->tx_cb);
	init_completion(&geni_mas->rx_cb);
	mutex_init(&geni_mas->spi_ssr.ssr_lock);
	pm_runtime_set_suspended(&pdev->dev);
	if (!geni_mas->dis_autosuspend) {
		pm_runtime_set_autosuspend_delay(&pdev->dev,
@@ -1691,6 +1771,12 @@ static int spi_geni_runtime_resume(struct device *dev)
	struct spi_master *spi = get_spi_master(dev);
	struct spi_geni_master *geni_mas = spi_master_get_devdata(spi);

	if (geni_mas->spi_ssr.is_ssr_down) {
		GENI_SE_ERR(geni_mas->ipc, false, NULL,
			"%s: Error runtime resume in SSR down\n", __func__);
		return -EAGAIN;
	}

	if (geni_mas->shared_se) {
		ret = se_geni_clks_on(&geni_mas->spi_rsc);
		if (ret)
@@ -1755,6 +1841,49 @@ static int spi_geni_suspend(struct device *dev)
}
#endif

static int ssr_spi_force_suspend(struct device *dev)
{
	struct spi_master *spi = get_spi_master(dev);
	struct spi_geni_master *mas = spi_master_get_devdata(spi);
	int ret = 0;

	mutex_lock(&mas->spi_ssr.ssr_lock);
	mas->spi_ssr.xfer_prepared = false;
	disable_irq(mas->irq);
	mas->spi_ssr.is_ssr_down = true;
	complete(&mas->xfer_done);

	if (!pm_runtime_status_suspended(mas->dev)) {
		ret = spi_geni_runtime_suspend(mas->dev);
		if (ret) {
			dev_err(mas->dev, "runtime suspend failed %d\n", ret);
		} else {
			pm_runtime_disable(mas->dev);
			pm_runtime_set_suspended(mas->dev);
			pm_runtime_enable(mas->dev);
		}
	}

	GENI_SE_DBG(mas->ipc, false, mas->dev, "force suspend done\n");
	mutex_unlock(&mas->spi_ssr.ssr_lock);

	return ret;
}

static int ssr_spi_force_resume(struct device *dev)
{
	struct spi_master *spi = get_spi_master(dev);
	struct spi_geni_master *mas = spi_master_get_devdata(spi);

	mutex_lock(&mas->spi_ssr.ssr_lock);
	mas->spi_ssr.is_ssr_down = false;
	enable_irq(mas->irq);
	GENI_SE_DBG(mas->ipc, false, mas->dev, "force resume done\n");
	mutex_unlock(&mas->spi_ssr.ssr_lock);

	return 0;
}

static const struct dev_pm_ops spi_geni_pm_ops = {
	SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend,
					spi_geni_runtime_resume, NULL)
+41 −2
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@
#include <linux/list.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
/* SSC Qup SSR related */
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/scm.h>

/* Transfer mode supported by GENI Serial Engines */
enum se_xfer_mode {
@@ -39,8 +42,43 @@ enum se_protocol_types {
	SPI_SLAVE
};

/* Notifier block Structure */
struct ssc_qup_nb {
	struct notifier_block nb;
	void *next; /*Notifier block pointer to next notifier block structure*/
};

/**
 * struct ssc_qup_ssr	GENI Serial Engine SSC qup SSR Structure.
 * @probe_completed	To ignore up notification during probe.
 * @is_ssr_down	To check SE status.
 * @subsys_name	Subsystem name for ssr registration.
 * @active_list_head	List Head of all client in SSC QUPv3.
 */
struct ssc_qup_ssr {
	struct ssc_qup_nb ssc_qup_nb;
	bool probe_completed;
	bool is_ssr_down;
	const char *subsys_name;
	struct list_head active_list_head;
};

/**
 * struct se_rsc_ssr	GENI Resource SSR Structure.
 * @active_list	List of SSC qup SE clients.
 * @force_suspend	Function pointer for Subsystem shutdown case.
 * @force_resume	Function pointer for Subsystem restart case.
 * @ssr_enable		To check SSC Qup SSR enable status.
 */
struct se_rsc_ssr {
	struct list_head active_list;
	int (*force_suspend)(struct device *ctrl_dev);
	int (*force_resume)(struct device *ctrl_dev);
	bool ssr_enable;
};

/**
 * struct geni_se_rsc - GENI Serial Engine Resource
 * struct se_geni_rsc - GENI Serial Engine Resource
 * @ctrl_dev		Pointer to controller device.
 * @wrapper_dev:	Pointer to the parent QUPv3 core.
 * @se_clk:		Handle to the core serial engine clock.
@@ -79,6 +117,7 @@ struct se_geni_rsc {
	struct pinctrl_state *geni_gpio_active;
	struct pinctrl_state *geni_gpio_sleep;
	int clk_freq_out;
	struct se_rsc_ssr rsc_ssr;
};

#define PINCTRL_DEFAULT	"default"
Loading