in spmi-pmic-arb.c [1260:1430]
static int spmi_pmic_arb_probe(struct platform_device *pdev)
{
struct spmi_pmic_arb *pmic_arb;
struct spmi_controller *ctrl;
struct resource *res;
void __iomem *core;
u32 *mapping_table;
u32 channel, ee, hw_ver;
int err;
ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
if (!ctrl)
return -ENOMEM;
pmic_arb = spmi_controller_get_drvdata(ctrl);
pmic_arb->spmic = ctrl;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
core = devm_ioremap_resource(&ctrl->dev, res);
if (IS_ERR(core)) {
err = PTR_ERR(core);
goto err_put_ctrl;
}
pmic_arb->core_size = resource_size(res);
pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID,
sizeof(*pmic_arb->ppid_to_apid),
GFP_KERNEL);
if (!pmic_arb->ppid_to_apid) {
err = -ENOMEM;
goto err_put_ctrl;
}
hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
if (hw_ver < PMIC_ARB_VERSION_V2_MIN) {
pmic_arb->ver_ops = &pmic_arb_v1;
pmic_arb->wr_base = core;
pmic_arb->rd_base = core;
} else {
pmic_arb->core = core;
if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
pmic_arb->ver_ops = &pmic_arb_v2;
else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
pmic_arb->ver_ops = &pmic_arb_v3;
else
pmic_arb->ver_ops = &pmic_arb_v5;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"obsrvr");
pmic_arb->rd_base = devm_ioremap_resource(&ctrl->dev, res);
if (IS_ERR(pmic_arb->rd_base)) {
err = PTR_ERR(pmic_arb->rd_base);
goto err_put_ctrl;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"chnls");
pmic_arb->wr_base = devm_ioremap_resource(&ctrl->dev, res);
if (IS_ERR(pmic_arb->wr_base)) {
err = PTR_ERR(pmic_arb->wr_base);
goto err_put_ctrl;
}
}
dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
pmic_arb->ver_ops->ver_str, hw_ver);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res);
if (IS_ERR(pmic_arb->intr)) {
err = PTR_ERR(pmic_arb->intr);
goto err_put_ctrl;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res);
if (IS_ERR(pmic_arb->cnfg)) {
err = PTR_ERR(pmic_arb->cnfg);
goto err_put_ctrl;
}
pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq");
if (pmic_arb->irq < 0) {
err = pmic_arb->irq;
goto err_put_ctrl;
}
err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
if (err) {
dev_err(&pdev->dev, "channel unspecified.\n");
goto err_put_ctrl;
}
if (channel > 5) {
dev_err(&pdev->dev, "invalid channel (%u) specified.\n",
channel);
err = -EINVAL;
goto err_put_ctrl;
}
pmic_arb->channel = channel;
err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee);
if (err) {
dev_err(&pdev->dev, "EE unspecified.\n");
goto err_put_ctrl;
}
if (ee > 5) {
dev_err(&pdev->dev, "invalid EE (%u) specified\n", ee);
err = -EINVAL;
goto err_put_ctrl;
}
pmic_arb->ee = ee;
mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS,
sizeof(*mapping_table), GFP_KERNEL);
if (!mapping_table) {
err = -ENOMEM;
goto err_put_ctrl;
}
pmic_arb->mapping_table = mapping_table;
/* Initialize max_apid/min_apid to the opposite bounds, during
* the irq domain translation, we are sure to update these */
pmic_arb->max_apid = 0;
pmic_arb->min_apid = PMIC_ARB_MAX_PERIPHS - 1;
platform_set_drvdata(pdev, ctrl);
raw_spin_lock_init(&pmic_arb->lock);
ctrl->cmd = pmic_arb_cmd;
ctrl->read_cmd = pmic_arb_read_cmd;
ctrl->write_cmd = pmic_arb_write_cmd;
if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
err = pmic_arb_read_apid_map_v5(pmic_arb);
if (err) {
dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n",
err);
goto err_put_ctrl;
}
}
dev_dbg(&pdev->dev, "adding irq domain\n");
pmic_arb->domain = irq_domain_add_tree(pdev->dev.of_node,
&pmic_arb_irq_domain_ops, pmic_arb);
if (!pmic_arb->domain) {
dev_err(&pdev->dev, "unable to create irq_domain\n");
err = -ENOMEM;
goto err_put_ctrl;
}
irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq,
pmic_arb);
err = spmi_controller_add(ctrl);
if (err)
goto err_domain_remove;
return 0;
err_domain_remove:
irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
irq_domain_remove(pmic_arb->domain);
err_put_ctrl:
spmi_controller_put(ctrl);
return err;
}