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

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

Merge "msm_serial_hs: Dynamic allocation of port structures"

parents 0f3ff5b5 06f38a1f
Loading
Loading
Loading
Loading
+90 −44
Original line number Diff line number Diff line
@@ -346,7 +346,6 @@ static struct of_device_id msm_hs_match_table[] = {
#define BLSP_UART_CLK_FMAX 63160000

static struct dentry *debug_base;
static struct msm_hs_port q_uart_port[UARTDM_NR];
static struct platform_driver msm_serial_hs_platform_driver;
static struct uart_driver msm_hs_driver;
static struct uart_ops msm_hs_ops;
@@ -354,6 +353,7 @@ static void msm_hs_start_rx_locked(struct uart_port *uport);
static void msm_serial_hs_rx_tlet(unsigned long tlet_ptr);
static void flip_insert_work(struct work_struct *work);
static void msm_hs_bus_voting(struct msm_hs_port *msm_uport, unsigned int vote);
static struct msm_hs_port *msm_hs_get_hs_port(int port_index);

#define UARTDM_TO_MSM(uart_port) \
	container_of((uart_port), struct msm_hs_port, uport)
@@ -456,50 +456,76 @@ static void msm_hs_clock_unvote(struct msm_hs_port *msm_uport)
	}
}

/* Check if the uport line number matches with user id stored in pdata.
 * User id information is stored during initialization. This function
 * ensues that the same device is selected */

static struct msm_hs_port *get_matching_hs_port(struct platform_device *pdev)
{
	struct msm_serial_hs_platform_data *pdata = pdev->dev.platform_data;
	struct msm_hs_port *msm_uport = msm_hs_get_hs_port(pdev->id);

	if ((!msm_uport) || (msm_uport->uport.line != pdev->id
	   && msm_uport->uport.line != pdata->userid)) {
		MSM_HS_ERR("uport line number mismatch!");
		WARN_ON(1);
		return NULL;
	}

	return msm_uport;
}

static ssize_t show_clock(struct device *dev, struct device_attribute *attr,
			  char *buf)
{
	int state = 1;
	ssize_t ret = 0;
	enum msm_hs_clk_states_e clk_state;
	unsigned long flags;

	struct platform_device *pdev = container_of(dev, struct
						    platform_device, dev);
	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);

	/* This check should not fail */
	if (msm_uport) {
		spin_lock_irqsave(&msm_uport->uport.lock, flags);
		clk_state = msm_uport->clk_state;
		spin_unlock_irqrestore(&msm_uport->uport.lock, flags);

		if (clk_state <= MSM_HS_CLK_OFF)
			state = 0;
		ret = snprintf(buf, PAGE_SIZE, "%d\n", state);
	}

	return snprintf(buf, PAGE_SIZE, "%d\n", state);
	return ret;
}

static ssize_t set_clock(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count)
{
	int state;
	ssize_t ret = 0;
	struct platform_device *pdev = container_of(dev, struct
						    platform_device, dev);
	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);

	/* This check should not fail */
	if (msm_uport) {
		state = buf[0] - '0';
		switch (state) {
	case 0: {
		case 0:
			msm_hs_request_clock_off(&msm_uport->uport);
			ret = count;
			break;
	}
	case 1: {
		case 1:
			msm_hs_request_clock_on(&msm_uport->uport);
			ret = count;
			break;
	}
	default: {
		return -EINVAL;
		default:
			ret = -EINVAL;
		}
	}
	return count;
	return ret;
}

static DEVICE_ATTR(clock, S_IWUSR | S_IRUGO, show_clock, set_clock);
@@ -727,9 +753,11 @@ static int msm_hs_remove(struct platform_device *pdev)
		return -EINVAL;
	}

	msm_uport = &q_uart_port[pdev->id];
	dev = msm_uport->uport.dev;
	msm_uport = get_matching_hs_port(pdev);
	if (!msm_uport)
		return -EINVAL;

	dev = msm_uport->uport.dev;
	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_clock.attr);
	debugfs_remove(msm_uport->loopback_dir);

@@ -2189,22 +2217,34 @@ static irqreturn_t msm_hs_isr(int irq, void *dev)
	return IRQ_HANDLED;
}

/*
 * Find UART device port using its port index value.
/* The following two functions provide interfaces to get the underlying
 * port structure (struct uart_port or struct msm_hs_port) given
 * the port index. msm_hs_get_uart port is called by clients.
 * The function msm_hs_get_hs_port is for internal use
 */

struct uart_port *msm_hs_get_uart_port(int port_index)
{
	int i;
	struct uart_state *state = msm_hs_driver.state + port_index;

	for (i = 0; i < UARTDM_NR; i++) {
		if (q_uart_port[i].uport.line == port_index)
			return &q_uart_port[i].uport;
	}
	/* The uart_driver structure stores the states in an array.
	 * Thus the corresponding offset from the drv->state returns
	 * the state for the uart_port that is requested */
	if (port_index == state->uart_port->line)
		return state->uart_port;

	return NULL;
}
EXPORT_SYMBOL(msm_hs_get_uart_port);

static struct msm_hs_port *msm_hs_get_hs_port(int port_index)
{
	struct uart_port *uport = msm_hs_get_uart_port(port_index);
	if (uport)
		return UARTDM_TO_MSM(uport);
	return NULL;
}

/* request to turn off uart clock once pending TX is flushed */
void msm_hs_request_clock_off(struct uart_port *uport) {
	unsigned long flags;
@@ -3093,7 +3133,9 @@ static int msm_hs_probe(struct platform_device *pdev)
		return -EINVAL;
	}

	msm_uport = &q_uart_port[pdev->id];
	msm_uport = devm_kzalloc(&pdev->dev, sizeof(struct msm_hs_port),
			GFP_KERNEL);
	msm_uport->uport.type = PORT_UNKNOWN;
	uport = &msm_uport->uport;
	uport->dev = &pdev->dev;

@@ -3349,17 +3391,12 @@ unmap_memory:
static int __init msm_serial_hs_init(void)
{
	int ret;
	int i;

	ipc_msm_hs_log_ctxt = ipc_log_context_create(IPC_MSM_HS_LOG_PAGES,
							"msm_serial_hs");
	if (!ipc_msm_hs_log_ctxt)
		MSM_HS_WARN("%s: error creating logging context", __func__);

	/* Init all UARTS as non-configured */
	for (i = 0; i < UARTDM_NR; i++)
		q_uart_port[i].uport.type = PORT_UNKNOWN;

	ret = uart_register_driver(&msm_hs_driver);
	if (unlikely(ret)) {
		MSM_HS_ERR("%s failed to load\n", __func__);
@@ -3500,8 +3537,13 @@ static int msm_hs_runtime_resume(struct device *dev)
{
	struct platform_device *pdev = container_of(dev, struct
						    platform_device, dev);
	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);

	/* This check should not fail
	 * During probe, we set uport->line to either pdev->id or userid */
	if (msm_uport)
		msm_hs_request_clock_on(&msm_uport->uport);

	return 0;
}

@@ -3509,7 +3551,11 @@ static int msm_hs_runtime_suspend(struct device *dev)
{
	struct platform_device *pdev = container_of(dev, struct
						    platform_device, dev);
	struct msm_hs_port *msm_uport = &q_uart_port[pdev->id];
	struct msm_hs_port *msm_uport = get_matching_hs_port(pdev);

	/* This check should not fail
	 * During probe, we set uport->line to either pdev->id or userid */
	if (msm_uport)
		msm_hs_request_clock_off(&msm_uport->uport);
	return 0;
}