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

Commit f180732a authored by Arjun Singh's avatar Arjun Singh
Browse files

soc: qcom: bgcom: add multiple client support



bgcom notifies all registered callbacks with interrupt event
and event data.

Signed-off-by: default avatarArjun Singh <arsingh@codeaurora.org>
Change-Id: I43bca65492f7ecaf7077597ec421748d04244ac2
parent c97f5cfd
Loading
Loading
Loading
Loading
+73 −62
Original line number Diff line number Diff line
@@ -65,25 +65,33 @@ struct bg_spi_priv {
	int irq_lock;
};

struct bg_context {
	struct bg_spi_priv *bg_spi;
	enum bgcom_state state;
};

struct cb_data {
	struct bg_context *handle;
	void *priv;
	void *handle;
	void (*bgcom_notification_cb)(void *handle, void *priv,
		enum bgcom_event_type event,
		union bgcom_event_data_type *event_data);
	struct list_head list;
};

static struct cb_data *irq_notification;
struct bg_context {
	struct bg_spi_priv *bg_spi;
	enum bgcom_state state;
	struct cb_data *cb;
};

static void *bg_com_drv;

static uint32_t g_slav_status_reg;

/* BGCOM client callbacks set-up */
static struct list_head cb_head = LIST_HEAD_INIT(cb_head);

static inline
void add_to_irq_list(struct  cb_data *data)
{
	list_add_tail(&data->list, &cb_head);
}

static bool is_bgcom_ready(void)
{
	return bg_com_drv ? true : false;
@@ -169,14 +177,20 @@ static int bgcom_transfer(void *handle, uint8_t *tx_buf,

/* BG-COM Interrupt handling */
static inline
void send_event(struct cb_data *cb,
		enum bgcom_event_type event, void *data)
void send_event(enum bgcom_event_type event,
	void *data)
{
	if (!cb)
		return;
	struct list_head *pos;
	struct cb_data *cb;

	/* send interrupt notification for each
	registered call-back */
	list_for_each(pos, &cb_head) {
		cb = list_entry(pos, struct cb_data, list);
		cb->bgcom_notification_cb(cb->handle,
		cb->priv,  event, data);
	}
}

static void send_back_notification(uint32_t slav_status_reg,
	uint32_t slav_status_auto_clear_reg,
@@ -192,73 +206,62 @@ static void send_back_notification(uint32_t slav_status_reg,
	slave_fifo_free = (uint16_t)(fifo_fill_reg >> 16);

	if (slav_status_auto_clear_reg & BIT(31))
		send_event(irq_notification,
			BGCOM_EVENT_RESET_OCCURRED, NULL);
		send_event(BGCOM_EVENT_RESET_OCCURRED, NULL);

	if (slav_status_auto_clear_reg & BIT(30))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, NULL);
		send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, NULL);

	if (slav_status_auto_clear_reg & BIT(29))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, NULL);
		send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, NULL);

	if (slav_status_auto_clear_reg & BIT(28))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, NULL);
		send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, NULL);

	if (slav_status_auto_clear_reg & BIT(27))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, NULL);
		send_event(BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, NULL);

	if (slav_status_auto_clear_reg & BIT(26))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, NULL);
		send_event(BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, NULL);

	if (slav_status_auto_clear_reg & BIT(25))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, NULL);
		send_event(BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, NULL);

	if (slav_status_auto_clear_reg & BIT(24))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_TRUNCATED_READ, NULL);
		send_event(BGCOM_EVENT_ERROR_TRUNCATED_READ, NULL);

	if (slav_status_auto_clear_reg & BIT(23))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_TRUNCATED_WRITE, NULL);
		send_event(BGCOM_EVENT_ERROR_TRUNCATED_WRITE, NULL);

	if (slav_status_auto_clear_reg & BIT(22))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, NULL);
		send_event(BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, NULL);

	if (slav_status_auto_clear_reg & BIT(21))
		send_event(irq_notification,
			BGCOM_EVENT_ERROR_AHB_BUS_ERR, NULL);
		send_event(BGCOM_EVENT_ERROR_AHB_BUS_ERR, NULL);

	/* check if BG status is changed */
	if (g_slav_status_reg ^ slav_status_reg) {
		if (slav_status_reg & BIT(30)) {
			event_data.application_running = true;
			send_event(irq_notification,
				BGCOM_EVENT_APPLICATION_RUNNING, &event_data);
			send_event(BGCOM_EVENT_APPLICATION_RUNNING,
				&event_data);
		}

		if (slav_status_reg & BIT(29)) {
			event_data.to_slave_fifo_ready = true;
			send_event(irq_notification,
				BGCOM_EVENT_TO_SLAVE_FIFO_READY, &event_data);
			send_event(BGCOM_EVENT_TO_SLAVE_FIFO_READY,
				&event_data);
		}

		if (slav_status_reg & BIT(28)) {
			event_data.to_master_fifo_ready = true;
			send_event(irq_notification,
				BGCOM_EVENT_TO_MASTER_FIFO_READY, &event_data);
			send_event(BGCOM_EVENT_TO_MASTER_FIFO_READY,
				&event_data);
		}

		if (slav_status_reg & BIT(27)) {
			event_data.ahb_ready = true;
			send_event(irq_notification,
				BGCOM_EVENT_AHB_READY, &event_data);
			send_event(BGCOM_EVENT_AHB_READY,
				&event_data);
		}
	}

@@ -272,8 +275,7 @@ static void send_back_notification(uint32_t slav_status_reg,
				event_data.fifo_data.to_master_fifo_used =
					master_fifo_used;
				event_data.fifo_data.data = ptr;
				send_event(irq_notification,
					BGCOM_EVENT_TO_MASTER_FIFO_USED,
				send_event(BGCOM_EVENT_TO_MASTER_FIFO_USED,
					&event_data);
			}
		}
@@ -281,8 +283,7 @@ static void send_back_notification(uint32_t slav_status_reg,

	if (slave_fifo_free > 0) {
		event_data.to_slave_fifo_free = slave_fifo_free;
		send_event(irq_notification,
			BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data);
		send_event(BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data);
	}
}

@@ -577,6 +578,7 @@ EXPORT_SYMBOL(bgcom_suspend);
void *bgcom_open(struct bgcom_open_config_type *open_config)
{
	struct bg_spi_priv *spi;
	struct cb_data *irq_notification;
	struct bg_context  *clnt_handle =
			kzalloc(sizeof(*clnt_handle), GFP_KERNEL);

@@ -592,33 +594,42 @@ void *bgcom_open(struct bgcom_open_config_type *open_config)
		clnt_handle->bg_spi = spi;
		clnt_handle->state = BGCOM_PROB_SUCCESS;
	}

	clnt_handle->cb = NULL;
	/* Interrupt callback Set-up */
	if (open_config && open_config->bgcom_notification_cb) {
		/* deregister the prevoius call-back */
		if (irq_notification) {
			pr_debug("freeing previous callback\n");
			kfree(irq_notification);
		}
		irq_notification = kzalloc(sizeof(*irq_notification),
			GFP_KERNEL);
		if (!irq_notification) {
			kfree(clnt_handle);
			return NULL;
		}
		if (!irq_notification)
			goto error_ret;

		/* set irq node */
		irq_notification->handle = clnt_handle;
		irq_notification->priv = open_config->priv;
		irq_notification->bgcom_notification_cb =
					open_config->bgcom_notification_cb;
		add_to_irq_list(irq_notification);
		clnt_handle->cb = irq_notification;
	}
	return clnt_handle;

error_ret:
	kfree(clnt_handle);
	return NULL;
}
EXPORT_SYMBOL(bgcom_open);

int bgcom_close(void **handle)
{
	struct bg_context *lhandle;
	struct cb_data *cb = NULL;

	if (*handle == NULL)
		return -EINVAL;
	lhandle = *handle;
	cb = lhandle->cb;
	if (cb)
		list_del(&cb->list);

	kfree(*handle);
	*handle = NULL;
	return 0;
@@ -628,8 +639,8 @@ EXPORT_SYMBOL(bgcom_close);
static irqreturn_t bg_irq_tasklet_hndlr(int irq, void *device)
{
	struct bg_spi_priv *bg_spi = device;

	if (!irq_notification || !irq_notification->bgcom_notification_cb) {
	/* check if call-back exists */
	if (list_empty(&cb_head)) {
		pr_debug("No callback registered\n");
		return IRQ_HANDLED;
	}