コード例 #1
0
ファイル: ucsi.c プロジェクト: the-snowwhite/linux-socfpga
/**
 * ucsi_unregister_ppm - Unregister UCSI PPM Interface
 * @ucsi: struct ucsi associated with the PPM
 *
 * Unregister UCSI PPM that was created with ucsi_register().
 */
void ucsi_unregister_ppm(struct ucsi *ucsi)
{
	struct ucsi_control ctrl;
	int i;

	/* Make sure that we are not in the middle of driver initialization */
	cancel_work_sync(&ucsi->work);

	mutex_lock(&ucsi->ppm_lock);

	/* Disable everything except command complete notification */
	UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE)
	ucsi_run_command(ucsi, &ctrl, NULL, 0);

	mutex_unlock(&ucsi->ppm_lock);

	for (i = 0; i < ucsi->cap.num_connectors; i++) {
		cancel_work_sync(&ucsi->connector[i].work);
		ucsi_unregister_partner(&ucsi->connector[i]);
		typec_unregister_port(ucsi->connector[i].port);
	}

	ucsi_reset_ppm(ucsi);

	kfree(ucsi->connector);
	kfree(ucsi);
}
コード例 #2
0
ファイル: ucsi.c プロジェクト: 513855417/linux
static int ucsi_acpi_remove(struct platform_device *pdev)
{
	struct ucsi *ucsi = platform_get_drvdata(pdev);

	acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
				   ACPI_ALL_NOTIFY, ucsi_acpi_notify);

	/* Make sure there are no events in the middle of being processed */
	if (wait_on_bit_timeout(&ucsi->flags, EVENT_PENDING,
				TASK_UNINTERRUPTIBLE,
				msecs_to_jiffies(UCSI_TIMEOUT_MS)))
		dev_WARN(ucsi->dev, "%s: Events still pending\n", __func__);

	ucsi_reset_ppm(ucsi);
	return 0;
}
コード例 #3
0
ファイル: ucsi.c プロジェクト: the-snowwhite/linux-socfpga
static int ucsi_role_cmd(struct ucsi_connector *con, struct ucsi_control *ctrl)
{
	int ret;

	ret = ucsi_run_command(con->ucsi, ctrl, NULL, 0);
	if (ret == -ETIMEDOUT) {
		struct ucsi_control c;

		/* PPM most likely stopped responding. Resetting everything. */
		ucsi_reset_ppm(con->ucsi);

		UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL);
		ucsi_run_command(con->ucsi, &c, NULL, 0);

		ucsi_reset_connector(con, true);
	}

	return ret;
}
コード例 #4
0
ファイル: ucsi.c プロジェクト: 513855417/linux
static int ucsi_init(struct ucsi *ucsi)
{
	struct ucsi_connector *con;
	struct ucsi_control ctrl;
	int ret;
	int i;

	init_completion(&ucsi->complete);
	spin_lock_init(&ucsi->dev_lock);
	mutex_init(&ucsi->ppm_lock);

	/* Reset the PPM */
	ret = ucsi_reset_ppm(ucsi);
	if (ret)
		return ret;

	/*
	 * REVISIT: Executing second reset to WA an issue seen on some of the
	 * Broxton based platforms, where the first reset puts the PPM into a
	 * state where it's unable to recognise some of the commands.
	 */
	ret = ucsi_reset_ppm(ucsi);
	if (ret)
		return ret;

	mutex_lock(&ucsi->ppm_lock);

	/* Enable basic notifications */
	ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE;
	ctrl.cmd.length = 0;
	ctrl.cmd.data = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
	ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0);
	if (ret)
		goto err_reset;

	/* Get PPM capabilities */
	ctrl.cmd.cmd = UCSI_GET_CAPABILITY;
	ret = ucsi_run_cmd(ucsi, &ctrl, &ucsi->cap, sizeof(ucsi->cap));
	if (ret)
		goto err_reset;

	if (!ucsi->cap.num_connectors) {
		ret = -ENODEV;
		goto err_reset;
	}

	ucsi->connector = devm_kcalloc(ucsi->dev, ucsi->cap.num_connectors,
				       sizeof(*ucsi->connector), GFP_KERNEL);
	if (!ucsi->connector) {
		ret = -ENOMEM;
		goto err_reset;
	}

	for (i = 1, con = ucsi->connector; i < ucsi->cap.num_connectors + 1;
	     i++, con++) {
		/* Get connector capability */
		ctrl.cmd.cmd = UCSI_GET_CONNECTOR_CAPABILITY;
		ctrl.cmd.data = i;
		ret = ucsi_run_cmd(ucsi, &ctrl, &con->cap, sizeof(con->cap));
		if (ret)
			goto err_reset;

		con->num = i;
		con->ucsi = ucsi;
		INIT_WORK(&con->work, ucsi_connector_change);
	}

	/* Enable all notifications */
	ctrl.cmd.cmd = UCSI_SET_NOTIFICATION_ENABLE;
	ctrl.cmd.data = UCSI_ENABLE_NTFY_ALL;
	ret = ucsi_run_cmd(ucsi, &ctrl, NULL, 0);
	if (ret < 0)
		goto err_reset;

	mutex_unlock(&ucsi->ppm_lock);
	return 0;
err_reset:
	ucsi_reset_ppm(ucsi);
	mutex_unlock(&ucsi->ppm_lock);
	return ret;
}
コード例 #5
0
ファイル: ucsi.c プロジェクト: the-snowwhite/linux-socfpga
static void ucsi_init(struct work_struct *work)
{
	struct ucsi *ucsi = container_of(work, struct ucsi, work);
	struct ucsi_connector *con;
	struct ucsi_control ctrl;
	int ret;
	int i;

	mutex_lock(&ucsi->ppm_lock);

	/* Reset the PPM */
	ret = ucsi_reset_ppm(ucsi);
	if (ret) {
		dev_err(ucsi->dev, "failed to reset PPM!\n");
		goto err;
	}

	/* Enable basic notifications */
	UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE |
					UCSI_ENABLE_NTFY_ERROR);
	ret = ucsi_run_command(ucsi, &ctrl, NULL, 0);
	if (ret < 0)
		goto err_reset;

	/* Get PPM capabilities */
	UCSI_CMD_GET_CAPABILITY(ctrl);
	ret = ucsi_run_command(ucsi, &ctrl, &ucsi->cap, sizeof(ucsi->cap));
	if (ret < 0)
		goto err_reset;

	if (!ucsi->cap.num_connectors) {
		ret = -ENODEV;
		goto err_reset;
	}

	/* Allocate the connectors. Released in ucsi_unregister_ppm() */
	ucsi->connector = kcalloc(ucsi->cap.num_connectors + 1,
				  sizeof(*ucsi->connector), GFP_KERNEL);
	if (!ucsi->connector) {
		ret = -ENOMEM;
		goto err_reset;
	}

	/* Register all connectors */
	for (i = 0; i < ucsi->cap.num_connectors; i++) {
		ret = ucsi_register_port(ucsi, i);
		if (ret)
			goto err_unregister;
	}

	/* Enable all notifications */
	UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
	ret = ucsi_run_command(ucsi, &ctrl, NULL, 0);
	if (ret < 0)
		goto err_unregister;

	mutex_unlock(&ucsi->ppm_lock);

	return;

err_unregister:
	for (con = ucsi->connector; con->port; con++) {
		ucsi_unregister_partner(con);
		typec_unregister_port(con->port);
		con->port = NULL;
	}

err_reset:
	ucsi_reset_ppm(ucsi);
err:
	mutex_unlock(&ucsi->ppm_lock);
	dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
}