in qcom_rpm.c [529:677]
static int qcom_rpm_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct device_node *syscon_np;
struct resource *res;
struct qcom_rpm *rpm;
u32 fw_version[3];
int irq_wakeup;
int irq_ack;
int irq_err;
int ret;
rpm = devm_kzalloc(&pdev->dev, sizeof(*rpm), GFP_KERNEL);
if (!rpm)
return -ENOMEM;
rpm->dev = &pdev->dev;
mutex_init(&rpm->lock);
init_completion(&rpm->ack);
/* Enable message RAM clock */
rpm->ramclk = devm_clk_get(&pdev->dev, "ram");
if (IS_ERR(rpm->ramclk)) {
ret = PTR_ERR(rpm->ramclk);
if (ret == -EPROBE_DEFER)
return ret;
/*
* Fall through in all other cases, as the clock is
* optional. (Does not exist on all platforms.)
*/
rpm->ramclk = NULL;
}
clk_prepare_enable(rpm->ramclk); /* Accepts NULL */
irq_ack = platform_get_irq_byname(pdev, "ack");
if (irq_ack < 0)
return irq_ack;
irq_err = platform_get_irq_byname(pdev, "err");
if (irq_err < 0)
return irq_err;
irq_wakeup = platform_get_irq_byname(pdev, "wakeup");
if (irq_wakeup < 0)
return irq_wakeup;
match = of_match_device(qcom_rpm_of_match, &pdev->dev);
if (!match)
return -ENODEV;
rpm->data = match->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rpm->status_regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(rpm->status_regs))
return PTR_ERR(rpm->status_regs);
rpm->ctrl_regs = rpm->status_regs + 0x400;
rpm->req_regs = rpm->status_regs + 0x600;
syscon_np = of_parse_phandle(pdev->dev.of_node, "qcom,ipc", 0);
if (!syscon_np) {
dev_err(&pdev->dev, "no qcom,ipc node\n");
return -ENODEV;
}
rpm->ipc_regmap = syscon_node_to_regmap(syscon_np);
of_node_put(syscon_np);
if (IS_ERR(rpm->ipc_regmap))
return PTR_ERR(rpm->ipc_regmap);
ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,ipc", 1,
&rpm->ipc_offset);
if (ret < 0) {
dev_err(&pdev->dev, "no offset in qcom,ipc\n");
return -EINVAL;
}
ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,ipc", 2,
&rpm->ipc_bit);
if (ret < 0) {
dev_err(&pdev->dev, "no bit in qcom,ipc\n");
return -EINVAL;
}
dev_set_drvdata(&pdev->dev, rpm);
fw_version[0] = readl(RPM_STATUS_REG(rpm, 0));
fw_version[1] = readl(RPM_STATUS_REG(rpm, 1));
fw_version[2] = readl(RPM_STATUS_REG(rpm, 2));
if (fw_version[0] != rpm->data->version) {
dev_err(&pdev->dev,
"RPM version %u.%u.%u incompatible with driver version %u",
fw_version[0],
fw_version[1],
fw_version[2],
rpm->data->version);
return -EFAULT;
}
writel(fw_version[0], RPM_CTRL_REG(rpm, 0));
writel(fw_version[1], RPM_CTRL_REG(rpm, 1));
writel(fw_version[2], RPM_CTRL_REG(rpm, 2));
dev_info(&pdev->dev, "RPM firmware %u.%u.%u\n", fw_version[0],
fw_version[1],
fw_version[2]);
ret = devm_request_irq(&pdev->dev,
irq_ack,
qcom_rpm_ack_interrupt,
IRQF_TRIGGER_RISING,
"qcom_rpm_ack",
rpm);
if (ret) {
dev_err(&pdev->dev, "failed to request ack interrupt\n");
return ret;
}
ret = irq_set_irq_wake(irq_ack, 1);
if (ret)
dev_warn(&pdev->dev, "failed to mark ack irq as wakeup\n");
ret = devm_request_irq(&pdev->dev,
irq_err,
qcom_rpm_err_interrupt,
IRQF_TRIGGER_RISING,
"qcom_rpm_err",
rpm);
if (ret) {
dev_err(&pdev->dev, "failed to request err interrupt\n");
return ret;
}
ret = devm_request_irq(&pdev->dev,
irq_wakeup,
qcom_rpm_wakeup_interrupt,
IRQF_TRIGGER_RISING,
"qcom_rpm_wakeup",
rpm);
if (ret) {
dev_err(&pdev->dev, "failed to request wakeup interrupt\n");
return ret;
}
ret = irq_set_irq_wake(irq_wakeup, 1);
if (ret)
dev_warn(&pdev->dev, "failed to mark wakeup irq as wakeup\n");
return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
}