int smd_core_platform_init(struct platform_device *pdev)
{
    int i;
    int ret;
    uint32_t num_ss;
    struct smd_platform *smd_platform_data;
    struct smd_subsystem_config *smd_ss_config_list;
    struct smd_subsystem_config *cfg;
    struct interrupt_config *private_intr_config;
    int err_ret = 0;

    smd_platform_data = pdev->dev.platform_data;
    num_ss = smd_platform_data->num_ss_configs;
    smd_ss_config_list = smd_platform_data->smd_ss_configs;

    if (smd_platform_data->smd_ssr_config)
        disable_smsm_reset_handshake = smd_platform_data->
                                       smd_ssr_config->disable_smsm_reset_handshake;

    for (i = 0; i < num_ss; i++) {
        cfg = &smd_ss_config_list[i];
        private_intr_config = smd_get_intr_config(cfg->edge);
        if (!private_intr_config) {
            pr_err("%s: invalid edge\n", __func__);
            goto intr_failed;
        }

        ret = intr_init(
                  &private_intr_config->smd,
                  &cfg->smd_int,
                  pdev
              );

        if (ret < 0) {
            err_ret = ret;
            pr_err("smd: register irq failed on %s\n",
                   cfg->smd_int.irq_name);
            goto intr_failed;
        }

        interrupt_stats[cfg->irq_config_id].smd_interrupt_id
            = cfg->smd_int.irq_id;

        if (cfg->smsm_int.irq_id)
            ret = intr_init(
                      &private_intr_config->smsm,
                      &cfg->smsm_int,
                      pdev
                  );

        if (ret < 0) {
            err_ret = ret;
            pr_err("smd: register irq failed on %s\n",
                   cfg->smsm_int.irq_name);
            goto intr_failed;
        }

        if (cfg->smsm_int.irq_id)
            interrupt_stats[cfg->irq_config_id].smsm_interrupt_id
                = cfg->smsm_int.irq_id;
        if (cfg->subsys_name)
            smd_set_edge_subsys_name(cfg->edge, cfg->subsys_name);

        smd_set_edge_initialized(cfg->edge);
    }

    SMD_INFO("smd_core_platform_init() done\n");

    return 0;

intr_failed:
    pr_err("smd: deregistering IRQs\n");
    for (i = 0; i < num_ss; ++i) {
        cfg = &smd_ss_config_list[i];

        if (cfg->smd_int.irq_id >= 0)
            free_irq(cfg->smd_int.irq_id,
                     (void *)cfg->smd_int.dev_id
                    );
        if (cfg->smsm_int.irq_id >= 0)
            free_irq(cfg->smsm_int.irq_id,
                     (void *)cfg->smsm_int.dev_id
                    );
    }
    return err_ret;
}
Пример #2
0
static int msm_smd_probe(struct platform_device *pdev)
{
	uint32_t edge;
	char *key;
	int ret;
	uint32_t irq_offset;
	uint32_t irq_bitmask;
	uint32_t irq_line;
	const char *pilstr;
	struct interrupt_config_item *private_irq;
	struct device_node *node;
	void *irq_out_base;
	resource_size_t irq_out_size;
	struct platform_device *parent_pdev;
	struct resource *r;
	struct interrupt_config *private_intr_config;
	uint32_t remote_pid;

	node = pdev->dev.of_node;

	if (!pdev->dev.parent) {
		pr_err("%s: missing link to parent device\n", __func__);
		return -ENODEV;
	}

	parent_pdev = to_platform_device(pdev->dev.parent);

	key = "irq-reg-base";
	r = platform_get_resource_byname(parent_pdev, IORESOURCE_MEM, key);
	if (!r)
		goto missing_key;
	irq_out_size = resource_size(r);
	irq_out_base = ioremap_nocache(r->start, irq_out_size);
	if (!irq_out_base) {
		pr_err("%s: ioremap_nocache() of irq_out_base addr:%pr size:%pr\n",
				__func__, &r->start, &irq_out_size);
		return -ENOMEM;
	}
	SMD_DBG("%s: %s = %p", __func__, key, irq_out_base);

	key = "qcom,smd-edge";
	ret = of_property_read_u32(node, key, &edge);
	if (ret)
		goto missing_key;
	SMD_DBG("%s: %s = %d", __func__, key, edge);

	key = "qcom,smd-irq-offset";
	ret = of_property_read_u32(node, key, &irq_offset);
	if (ret)
		goto missing_key;
	SMD_DBG("%s: %s = %x", __func__, key, irq_offset);

	key = "qcom,smd-irq-bitmask";
	ret = of_property_read_u32(node, key, &irq_bitmask);
	if (ret)
		goto missing_key;
	SMD_DBG("%s: %s = %x", __func__, key, irq_bitmask);

	key = "interrupts";
	irq_line = irq_of_parse_and_map(node, 0);
	if (!irq_line)
		goto missing_key;
	SMD_DBG("%s: %s = %d", __func__, key, irq_line);

	key = "qcom,pil-string";
	pilstr = of_get_property(node, key, NULL);
	if (pilstr)
		SMD_DBG("%s: %s = %s", __func__, key, pilstr);

	private_intr_config = smd_get_intr_config(edge);
	if (!private_intr_config) {
		pr_err("%s: invalid edge\n", __func__);
		return -ENODEV;
	}
	private_irq = &private_intr_config->smd;
	private_irq->out_bit_pos = irq_bitmask;
	private_irq->out_offset = irq_offset;
	private_irq->out_base = irq_out_base;
	private_irq->irq_id = irq_line;
	remote_pid = smd_edge_to_remote_pid(edge);
	interrupt_stats[remote_pid].smd_interrupt_id = irq_line;

	ret = request_irq(irq_line,
				private_irq->irq_handler,
				IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
				"smd_dev",
				NULL);
	if (ret < 0) {
		pr_err("%s: request_irq() failed on %d\n", __func__, irq_line);
		return ret;
	} else {
		ret = enable_irq_wake(irq_line);
		if (ret < 0)
			pr_err("%s: enable_irq_wake() failed on %d\n", __func__,
					irq_line);
	}

	if (pilstr)
		smd_set_edge_subsys_name(edge, pilstr);

	smd_set_edge_initialized(edge);
	smd_post_init(0, remote_pid);
	return 0;

missing_key:
	pr_err("%s: missing key: %s", __func__, key);
	return -ENODEV;
}