/* arch/arm/mach-msm/smd_init_dt.c * * Copyright (c) 2013, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #ifdef CONFIG_OF #include #include #include #include #include #include #include #include #define MODULE_NAME "msm_smd" #define IPC_LOG(level, x...) do { \ if (smd_log_ctx) \ ipc_log_string(smd_log_ctx, x); \ else \ printk(level x); \ } while (0) #if defined(CONFIG_MSM_SMD_DEBUG) #define SMD_DBG(x...) do { \ if (msm_smd_debug_mask & MSM_SMD_DEBUG) \ IPC_LOG(KERN_DEBUG, x); \ } while (0) #define SMSM_DBG(x...) do { \ if (msm_smd_debug_mask & MSM_SMSM_DEBUG) \ IPC_LOG(KERN_DEBUG, x); \ } while (0) #else #define SMD_DBG(x...) do { } while (0) #define SMSM_DBG(x...) do { } while (0) #endif static int msm_smsm_probe(struct platform_device *pdev) { uint32_t edge; char *key; int ret; uint32_t irq_offset; uint32_t irq_bitmask; uint32_t irq_line; 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; disable_smsm_reset_handshake = 1; 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; } SMSM_DBG("%s: %s = %p", __func__, key, irq_out_base); key = "qcom,smsm-edge"; ret = of_property_read_u32(node, key, &edge); if (ret) goto missing_key; SMSM_DBG("%s: %s = %d", __func__, key, edge); key = "qcom,smsm-irq-offset"; ret = of_property_read_u32(node, key, &irq_offset); if (ret) goto missing_key; SMSM_DBG("%s: %s = %x", __func__, key, irq_offset); key = "qcom,smsm-irq-bitmask"; ret = of_property_read_u32(node, key, &irq_bitmask); if (ret) goto missing_key; SMSM_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; SMSM_DBG("%s: %s = %d", __func__, key, irq_line); 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->smsm; 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].smsm_interrupt_id = irq_line; ret = request_irq(irq_line, private_irq->irq_handler, IRQF_TRIGGER_RISING, "smsm_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); } ret = smsm_post_init(); if (ret) { pr_err("smd_post_init() failed ret=%d\n", ret); return ret; } return 0; missing_key: pr_err("%s: missing key: %s", __func__, key); return -ENODEV; } 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; unsigned long irq_flags = IRQF_TRIGGER_RISING; 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); key = "qcom,irq-no-suspend"; ret = of_property_read_bool(node, key); if (ret) irq_flags |= IRQF_NO_SUSPEND; 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, irq_flags, "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); return 0; missing_key: pr_err("%s: missing key: %s", __func__, key); return -ENODEV; } static struct of_device_id msm_smd_match_table[] = { { .compatible = "qcom,smd" }, {}, }; static struct platform_driver msm_smd_driver = { .probe = msm_smd_probe, .driver = { .name = MODULE_NAME , .owner = THIS_MODULE, .of_match_table = msm_smd_match_table, }, }; static struct of_device_id msm_smsm_match_table[] = { { .compatible = "qcom,smsm" }, {}, }; static struct platform_driver msm_smsm_driver = { .probe = msm_smsm_probe, .driver = { .name = "msm_smsm", .owner = THIS_MODULE, .of_match_table = msm_smsm_match_table, }, }; int msm_smd_driver_register(void) { int rc; rc = platform_driver_register(&msm_smd_driver); if (rc) { pr_err("%s: smd_driver register failed %d\n", __func__, rc); return rc; } rc = platform_driver_register(&msm_smsm_driver); if (rc) { pr_err("%s: msm_smsm_driver register failed %d\n", __func__, rc); return rc; } return 0; } EXPORT_SYMBOL(msm_smd_driver_register); MODULE_DESCRIPTION("MSM SMD Device Tree Init"); MODULE_LICENSE("GPL v2"); #endif