blob: 640656cbb51573c1d53f731666cff86d0aa21903 [file] [log] [blame]
/* 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 <linux/platform_device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <mach/msm_ipc_logging.h>
#include <smd_private.h>
#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, remote_pid);
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